mirror of
https://github.com/wled/WLED.git
synced 2025-07-16 23:36:35 +00:00
Merge branch 'main' into waterfall-fix
This commit is contained in:
commit
f001846e00
7
package-lock.json
generated
7
package-lock.json
generated
@ -1,18 +1,21 @@
|
|||||||
{
|
{
|
||||||
"name": "wled",
|
"name": "wled",
|
||||||
"version": "0.15.0-b7",
|
"version": "0.16.0-dev",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "wled",
|
"name": "wled",
|
||||||
"version": "0.15.0-b7",
|
"version": "0.16.0-dev",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"clean-css": "^5.3.3",
|
"clean-css": "^5.3.3",
|
||||||
"html-minifier-terser": "^7.2.0",
|
"html-minifier-terser": "^7.2.0",
|
||||||
"inliner": "^1.13.1",
|
"inliner": "^1.13.1",
|
||||||
"nodemon": "^3.1.7"
|
"nodemon": "^3.1.7"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=20.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@jridgewell/gen-mapping": {
|
"node_modules/@jridgewell/gen-mapping": {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "wled",
|
"name": "wled",
|
||||||
"version": "0.15.0-dev",
|
"version": "0.16.0-dev",
|
||||||
"description": "Tools for WLED project",
|
"description": "Tools for WLED project",
|
||||||
"main": "tools/cdata.js",
|
"main": "tools/cdata.js",
|
||||||
"directories": {
|
"directories": {
|
||||||
|
@ -49,7 +49,7 @@ private:
|
|||||||
|
|
||||||
void setColor(int r, int g, int b)
|
void setColor(int r, int g, int b)
|
||||||
{
|
{
|
||||||
strip.setColor(0, r, g, b);
|
strip.getMainSegment().setColor(0, RGBW32(r, g, b, 0));
|
||||||
stateUpdated(CALL_MODE_DIRECT_CHANGE);
|
stateUpdated(CALL_MODE_DIRECT_CHANGE);
|
||||||
char msg[18] {};
|
char msg[18] {};
|
||||||
sprintf(msg, "rgb(%d,%d,%d)", r, g, b);
|
sprintf(msg, "rgb(%d,%d,%d)", r, g, b);
|
||||||
|
@ -31,14 +31,14 @@ public:
|
|||||||
//strip.getSegment(1).setOption(SEG_OPTION_SELECTED, true);
|
//strip.getSegment(1).setOption(SEG_OPTION_SELECTED, true);
|
||||||
|
|
||||||
//select first two segments (background color + FX settable)
|
//select first two segments (background color + FX settable)
|
||||||
WS2812FX::Segment &seg = strip.getSegment(0);
|
Segment &seg = strip.getSegment(0);
|
||||||
seg.colors[0] = ((0 << 24) | ((0 & 0xFF) << 16) | ((0 & 0xFF) << 8) | ((0 & 0xFF)));
|
seg.colors[0] = ((0 << 24) | ((0 & 0xFF) << 16) | ((0 & 0xFF) << 8) | ((0 & 0xFF)));
|
||||||
strip.getSegment(0).setOption(0, false);
|
strip.getSegment(0).setOption(0, false);
|
||||||
strip.getSegment(0).setOption(2, false);
|
strip.getSegment(0).setOption(2, false);
|
||||||
//other segments are text
|
//other segments are text
|
||||||
for (int i = 1; i < 10; i++)
|
for (int i = 1; i < 10; i++)
|
||||||
{
|
{
|
||||||
WS2812FX::Segment &seg = strip.getSegment(i);
|
Segment &seg = strip.getSegment(i);
|
||||||
seg.colors[0] = ((0 << 24) | ((0 & 0xFF) << 16) | ((190 & 0xFF) << 8) | ((180 & 0xFF)));
|
seg.colors[0] = ((0 << 24) | ((0 & 0xFF) << 16) | ((190 & 0xFF) << 8) | ((180 & 0xFF)));
|
||||||
strip.getSegment(i).setOption(0, true);
|
strip.getSegment(i).setOption(0, true);
|
||||||
strip.setBrightness(64);
|
strip.setBrightness(64);
|
||||||
@ -80,61 +80,61 @@ public:
|
|||||||
void displayTime(byte hour, byte minute)
|
void displayTime(byte hour, byte minute)
|
||||||
{
|
{
|
||||||
bool isToHour = false; //true if minute > 30
|
bool isToHour = false; //true if minute > 30
|
||||||
strip.setSegment(0, 0, 64); // background
|
strip.getSegment(0).setGeometry(0, 64); // background
|
||||||
strip.setSegment(1, 0, 2); //It is
|
strip.getSegment(1).setGeometry(0, 2); //It is
|
||||||
|
|
||||||
strip.setSegment(2, 0, 0);
|
strip.getSegment(2).setGeometry(0, 0);
|
||||||
strip.setSegment(3, 0, 0); //disable minutes
|
strip.getSegment(3).setGeometry(0, 0); //disable minutes
|
||||||
strip.setSegment(4, 0, 0); //past
|
strip.getSegment(4).setGeometry(0, 0); //past
|
||||||
strip.setSegment(6, 0, 0); //to
|
strip.getSegment(6).setGeometry(0, 0); //to
|
||||||
strip.setSegment(8, 0, 0); //disable o'clock
|
strip.getSegment(8).setGeometry(0, 0); //disable o'clock
|
||||||
|
|
||||||
if (hour < 24) //valid time, display
|
if (hour < 24) //valid time, display
|
||||||
{
|
{
|
||||||
if (minute == 30)
|
if (minute == 30)
|
||||||
{
|
{
|
||||||
strip.setSegment(2, 3, 6); //half
|
strip.getSegment(2).setGeometry(3, 6); //half
|
||||||
strip.setSegment(3, 0, 0); //minutes
|
strip.getSegment(3).setGeometry(0, 0); //minutes
|
||||||
}
|
}
|
||||||
else if (minute == 15 || minute == 45)
|
else if (minute == 15 || minute == 45)
|
||||||
{
|
{
|
||||||
strip.setSegment(3, 0, 0); //minutes
|
strip.getSegment(3).setGeometry(0, 0); //minutes
|
||||||
}
|
}
|
||||||
else if (minute == 10)
|
else if (minute == 10)
|
||||||
{
|
{
|
||||||
//strip.setSegment(5, 6, 8); //ten
|
//strip.getSegment(5).setGeometry(6, 8); //ten
|
||||||
}
|
}
|
||||||
else if (minute == 5)
|
else if (minute == 5)
|
||||||
{
|
{
|
||||||
//strip.setSegment(5, 16, 18); //five
|
//strip.getSegment(5).setGeometry(16, 18); //five
|
||||||
}
|
}
|
||||||
else if (minute == 0)
|
else if (minute == 0)
|
||||||
{
|
{
|
||||||
strip.setSegment(3, 0, 0); //minutes
|
strip.getSegment(3).setGeometry(0, 0); //minutes
|
||||||
//hourChime();
|
//hourChime();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
strip.setSegment(3, 18, 22); //minutes
|
strip.getSegment(3).setGeometry(18, 22); //minutes
|
||||||
}
|
}
|
||||||
|
|
||||||
//past or to?
|
//past or to?
|
||||||
if (minute == 0)
|
if (minute == 0)
|
||||||
{ //full hour
|
{ //full hour
|
||||||
strip.setSegment(3, 0, 0); //disable minutes
|
strip.getSegment(3).setGeometry(0, 0); //disable minutes
|
||||||
strip.setSegment(4, 0, 0); //disable past
|
strip.getSegment(4).setGeometry(0, 0); //disable past
|
||||||
strip.setSegment(6, 0, 0); //disable to
|
strip.getSegment(6).setGeometry(0, 0); //disable to
|
||||||
strip.setSegment(8, 60, 64); //o'clock
|
strip.getSegment(8).setGeometry(60, 64); //o'clock
|
||||||
}
|
}
|
||||||
else if (minute > 34)
|
else if (minute > 34)
|
||||||
{
|
{
|
||||||
//strip.setSegment(6, 22, 24); //to
|
//strip.getSegment(6).setGeometry(22, 24); //to
|
||||||
//minute = 60 - minute;
|
//minute = 60 - minute;
|
||||||
isToHour = true;
|
isToHour = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//strip.setSegment(4, 24, 27); //past
|
//strip.getSegment(4).setGeometry(24, 27); //past
|
||||||
//isToHour = false;
|
//isToHour = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -143,68 +143,68 @@ public:
|
|||||||
|
|
||||||
if (minute <= 4)
|
if (minute <= 4)
|
||||||
{
|
{
|
||||||
strip.setSegment(3, 0, 0); //nothing
|
strip.getSegment(3).setGeometry(0, 0); //nothing
|
||||||
strip.setSegment(5, 0, 0); //nothing
|
strip.getSegment(5).setGeometry(0, 0); //nothing
|
||||||
strip.setSegment(6, 0, 0); //nothing
|
strip.getSegment(6).setGeometry(0, 0); //nothing
|
||||||
strip.setSegment(8, 60, 64); //o'clock
|
strip.getSegment(8).setGeometry(60, 64); //o'clock
|
||||||
}
|
}
|
||||||
else if (minute <= 9)
|
else if (minute <= 9)
|
||||||
{
|
{
|
||||||
strip.setSegment(5, 16, 18); // five past
|
strip.getSegment(5).setGeometry(16, 18); // five past
|
||||||
strip.setSegment(4, 24, 27); //past
|
strip.getSegment(4).setGeometry(24, 27); //past
|
||||||
}
|
}
|
||||||
else if (minute <= 14)
|
else if (minute <= 14)
|
||||||
{
|
{
|
||||||
strip.setSegment(5, 6, 8); // ten past
|
strip.getSegment(5).setGeometry(6, 8); // ten past
|
||||||
strip.setSegment(4, 24, 27); //past
|
strip.getSegment(4).setGeometry(24, 27); //past
|
||||||
}
|
}
|
||||||
else if (minute <= 19)
|
else if (minute <= 19)
|
||||||
{
|
{
|
||||||
strip.setSegment(5, 8, 12); // quarter past
|
strip.getSegment(5).setGeometry(8, 12); // quarter past
|
||||||
strip.setSegment(3, 0, 0); //minutes
|
strip.getSegment(3).setGeometry(0, 0); //minutes
|
||||||
strip.setSegment(4, 24, 27); //past
|
strip.getSegment(4).setGeometry(24, 27); //past
|
||||||
}
|
}
|
||||||
else if (minute <= 24)
|
else if (minute <= 24)
|
||||||
{
|
{
|
||||||
strip.setSegment(5, 12, 16); // twenty past
|
strip.getSegment(5).setGeometry(12, 16); // twenty past
|
||||||
strip.setSegment(4, 24, 27); //past
|
strip.getSegment(4).setGeometry(24, 27); //past
|
||||||
}
|
}
|
||||||
else if (minute <= 29)
|
else if (minute <= 29)
|
||||||
{
|
{
|
||||||
strip.setSegment(5, 12, 18); // twenty-five past
|
strip.getSegment(5).setGeometry(12, 18); // twenty-five past
|
||||||
strip.setSegment(4, 24, 27); //past
|
strip.getSegment(4).setGeometry(24, 27); //past
|
||||||
}
|
}
|
||||||
else if (minute <= 34)
|
else if (minute <= 34)
|
||||||
{
|
{
|
||||||
strip.setSegment(5, 3, 6); // half past
|
strip.getSegment(5).setGeometry(3, 6); // half past
|
||||||
strip.setSegment(3, 0, 0); //minutes
|
strip.getSegment(3).setGeometry(0, 0); //minutes
|
||||||
strip.setSegment(4, 24, 27); //past
|
strip.getSegment(4).setGeometry(24, 27); //past
|
||||||
}
|
}
|
||||||
else if (minute <= 39)
|
else if (minute <= 39)
|
||||||
{
|
{
|
||||||
strip.setSegment(5, 12, 18); // twenty-five to
|
strip.getSegment(5).setGeometry(12, 18); // twenty-five to
|
||||||
strip.setSegment(6, 22, 24); //to
|
strip.getSegment(6).setGeometry(22, 24); //to
|
||||||
}
|
}
|
||||||
else if (minute <= 44)
|
else if (minute <= 44)
|
||||||
{
|
{
|
||||||
strip.setSegment(5, 12, 16); // twenty to
|
strip.getSegment(5).setGeometry(12, 16); // twenty to
|
||||||
strip.setSegment(6, 22, 24); //to
|
strip.getSegment(6).setGeometry(22, 24); //to
|
||||||
}
|
}
|
||||||
else if (minute <= 49)
|
else if (minute <= 49)
|
||||||
{
|
{
|
||||||
strip.setSegment(5, 8, 12); // quarter to
|
strip.getSegment(5).setGeometry(8, 12); // quarter to
|
||||||
strip.setSegment(3, 0, 0); //minutes
|
strip.getSegment(3).setGeometry(0, 0); //minutes
|
||||||
strip.setSegment(6, 22, 24); //to
|
strip.getSegment(6).setGeometry(22, 24); //to
|
||||||
}
|
}
|
||||||
else if (minute <= 54)
|
else if (minute <= 54)
|
||||||
{
|
{
|
||||||
strip.setSegment(5, 6, 8); // ten to
|
strip.getSegment(5).setGeometry(6, 8); // ten to
|
||||||
strip.setSegment(6, 22, 24); //to
|
strip.getSegment(6).setGeometry(22, 24); //to
|
||||||
}
|
}
|
||||||
else if (minute <= 59)
|
else if (minute <= 59)
|
||||||
{
|
{
|
||||||
strip.setSegment(5, 16, 18); // five to
|
strip.getSegment(5).setGeometry(16, 18); // five to
|
||||||
strip.setSegment(6, 22, 24); //to
|
strip.getSegment(6).setGeometry(22, 24); //to
|
||||||
}
|
}
|
||||||
|
|
||||||
//hours
|
//hours
|
||||||
@ -220,45 +220,45 @@ public:
|
|||||||
switch (hour)
|
switch (hour)
|
||||||
{
|
{
|
||||||
case 1:
|
case 1:
|
||||||
strip.setSegment(7, 27, 29);
|
strip.getSegment(7).setGeometry(27, 29);
|
||||||
break; //one
|
break; //one
|
||||||
case 2:
|
case 2:
|
||||||
strip.setSegment(7, 35, 37);
|
strip.getSegment(7).setGeometry(35, 37);
|
||||||
break; //two
|
break; //two
|
||||||
case 3:
|
case 3:
|
||||||
strip.setSegment(7, 29, 32);
|
strip.getSegment(7).setGeometry(29, 32);
|
||||||
break; //three
|
break; //three
|
||||||
case 4:
|
case 4:
|
||||||
strip.setSegment(7, 32, 35);
|
strip.getSegment(7).setGeometry(32, 35);
|
||||||
break; //four
|
break; //four
|
||||||
case 5:
|
case 5:
|
||||||
strip.setSegment(7, 37, 40);
|
strip.getSegment(7).setGeometry(37, 40);
|
||||||
break; //five
|
break; //five
|
||||||
case 6:
|
case 6:
|
||||||
strip.setSegment(7, 43, 45);
|
strip.getSegment(7).setGeometry(43, 45);
|
||||||
break; //six
|
break; //six
|
||||||
case 7:
|
case 7:
|
||||||
strip.setSegment(7, 40, 43);
|
strip.getSegment(7).setGeometry(40, 43);
|
||||||
break; //seven
|
break; //seven
|
||||||
case 8:
|
case 8:
|
||||||
strip.setSegment(7, 45, 48);
|
strip.getSegment(7).setGeometry(45, 48);
|
||||||
break; //eight
|
break; //eight
|
||||||
case 9:
|
case 9:
|
||||||
strip.setSegment(7, 48, 50);
|
strip.getSegment(7).setGeometry(48, 50);
|
||||||
break; //nine
|
break; //nine
|
||||||
case 10:
|
case 10:
|
||||||
strip.setSegment(7, 54, 56);
|
strip.getSegment(7).setGeometry(54, 56);
|
||||||
break; //ten
|
break; //ten
|
||||||
case 11:
|
case 11:
|
||||||
strip.setSegment(7, 50, 54);
|
strip.getSegment(7).setGeometry(50, 54);
|
||||||
break; //eleven
|
break; //eleven
|
||||||
case 12:
|
case 12:
|
||||||
strip.setSegment(7, 56, 60);
|
strip.getSegment(7).setGeometry(56, 60);
|
||||||
break; //twelve
|
break; //twelve
|
||||||
}
|
}
|
||||||
|
|
||||||
selectWordSegments(true);
|
selectWordSegments(true);
|
||||||
applyMacro(1);
|
applyPreset(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void timeOfDay()
|
void timeOfDay()
|
||||||
|
@ -1,305 +0,0 @@
|
|||||||
#include "wled.h"
|
|
||||||
/*
|
|
||||||
* This v1 usermod file allows you to add own functionality to WLED more easily
|
|
||||||
* See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality
|
|
||||||
* EEPROM bytes 2750+ are reserved for your custom use case. (if you extend #define EEPSIZE in const.h)
|
|
||||||
* If you just need 8 bytes, use 2551-2559 (you do not need to increase EEPSIZE)
|
|
||||||
*
|
|
||||||
* Consider the v2 usermod API if you need a more advanced feature set!
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
uint8_t minuteLast = 99;
|
|
||||||
int dayBrightness = 128;
|
|
||||||
int nightBrightness = 16;
|
|
||||||
|
|
||||||
//Use userVar0 and userVar1 (API calls &U0=,&U1=, uint16_t)
|
|
||||||
|
|
||||||
//gets called once at boot. Do all initialization that doesn't depend on network here
|
|
||||||
void userSetup()
|
|
||||||
{
|
|
||||||
saveMacro(14, "A=128", false);
|
|
||||||
saveMacro(15, "A=64", false);
|
|
||||||
saveMacro(16, "A=16", false);
|
|
||||||
|
|
||||||
saveMacro(1, "&FX=0&R=255&G=255&B=255", false);
|
|
||||||
|
|
||||||
//strip.getSegment(1).setOption(SEG_OPTION_SELECTED, true);
|
|
||||||
|
|
||||||
//select first two segments (background color + FX settable)
|
|
||||||
Segment &seg = strip.getSegment(0);
|
|
||||||
seg.colors[0] = ((0 << 24) | ((0 & 0xFF) << 16) | ((0 & 0xFF) << 8) | ((0 & 0xFF)));
|
|
||||||
strip.getSegment(0).setOption(0, false);
|
|
||||||
strip.getSegment(0).setOption(2, false);
|
|
||||||
//other segments are text
|
|
||||||
for (int i = 1; i < 10; i++)
|
|
||||||
{
|
|
||||||
Segment &seg = strip.getSegment(i);
|
|
||||||
seg.colors[0] = ((0 << 24) | ((0 & 0xFF) << 16) | ((190 & 0xFF) << 8) | ((180 & 0xFF)));
|
|
||||||
strip.getSegment(i).setOption(0, true);
|
|
||||||
strip.setBrightness(128);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//gets called every time WiFi is (re-)connected. Initialize own network interfaces here
|
|
||||||
void userConnected()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void selectWordSegments(bool state)
|
|
||||||
{
|
|
||||||
for (int i = 1; i < 10; i++)
|
|
||||||
{
|
|
||||||
//Segment &seg = strip.getSegment(i);
|
|
||||||
strip.getSegment(i).setOption(0, state);
|
|
||||||
// strip.getSegment(1).setOption(SEG_OPTION_SELECTED, true);
|
|
||||||
//seg.mode = 12;
|
|
||||||
//seg.palette = 1;
|
|
||||||
//strip.setBrightness(255);
|
|
||||||
}
|
|
||||||
strip.getSegment(0).setOption(0, !state);
|
|
||||||
}
|
|
||||||
|
|
||||||
void hourChime()
|
|
||||||
{
|
|
||||||
//strip.resetSegments();
|
|
||||||
selectWordSegments(true);
|
|
||||||
colorUpdated(CALL_MODE_FX_CHANGED);
|
|
||||||
//savePreset(255);
|
|
||||||
selectWordSegments(false);
|
|
||||||
//strip.getSegment(0).setOption(0, true);
|
|
||||||
strip.getSegment(0).setOption(2, true);
|
|
||||||
applyPreset(12);
|
|
||||||
colorUpdated(CALL_MODE_FX_CHANGED);
|
|
||||||
}
|
|
||||||
|
|
||||||
void displayTime(byte hour, byte minute)
|
|
||||||
{
|
|
||||||
bool isToHour = false; //true if minute > 30
|
|
||||||
strip.setSegment(0, 0, 64); // background
|
|
||||||
strip.setSegment(1, 0, 2); //It is
|
|
||||||
|
|
||||||
strip.setSegment(2, 0, 0);
|
|
||||||
strip.setSegment(3, 0, 0); //disable minutes
|
|
||||||
strip.setSegment(4, 0, 0); //past
|
|
||||||
strip.setSegment(6, 0, 0); //to
|
|
||||||
strip.setSegment(8, 0, 0); //disable o'clock
|
|
||||||
|
|
||||||
if (hour < 24) //valid time, display
|
|
||||||
{
|
|
||||||
if (minute == 30)
|
|
||||||
{
|
|
||||||
strip.setSegment(2, 3, 6); //half
|
|
||||||
strip.setSegment(3, 0, 0); //minutes
|
|
||||||
}
|
|
||||||
else if (minute == 15 || minute == 45)
|
|
||||||
{
|
|
||||||
strip.setSegment(3, 0, 0); //minutes
|
|
||||||
}
|
|
||||||
else if (minute == 10)
|
|
||||||
{
|
|
||||||
//strip.setSegment(5, 6, 8); //ten
|
|
||||||
}
|
|
||||||
else if (minute == 5)
|
|
||||||
{
|
|
||||||
//strip.setSegment(5, 16, 18); //five
|
|
||||||
}
|
|
||||||
else if (minute == 0)
|
|
||||||
{
|
|
||||||
strip.setSegment(3, 0, 0); //minutes
|
|
||||||
//hourChime();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
strip.setSegment(3, 18, 22); //minutes
|
|
||||||
}
|
|
||||||
|
|
||||||
//past or to?
|
|
||||||
if (minute == 0)
|
|
||||||
{ //full hour
|
|
||||||
strip.setSegment(3, 0, 0); //disable minutes
|
|
||||||
strip.setSegment(4, 0, 0); //disable past
|
|
||||||
strip.setSegment(6, 0, 0); //disable to
|
|
||||||
strip.setSegment(8, 60, 64); //o'clock
|
|
||||||
}
|
|
||||||
else if (minute > 34)
|
|
||||||
{
|
|
||||||
//strip.setSegment(6, 22, 24); //to
|
|
||||||
//minute = 60 - minute;
|
|
||||||
isToHour = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//strip.setSegment(4, 24, 27); //past
|
|
||||||
//isToHour = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{ //temperature display
|
|
||||||
}
|
|
||||||
|
|
||||||
//byte minuteRem = minute %10;
|
|
||||||
|
|
||||||
if (minute <= 4)
|
|
||||||
{
|
|
||||||
strip.setSegment(3, 0, 0); //nothing
|
|
||||||
strip.setSegment(5, 0, 0); //nothing
|
|
||||||
strip.setSegment(6, 0, 0); //nothing
|
|
||||||
strip.setSegment(8, 60, 64); //o'clock
|
|
||||||
}
|
|
||||||
else if (minute <= 9)
|
|
||||||
{
|
|
||||||
strip.setSegment(5, 16, 18); // five past
|
|
||||||
strip.setSegment(4, 24, 27); //past
|
|
||||||
}
|
|
||||||
else if (minute <= 14)
|
|
||||||
{
|
|
||||||
strip.setSegment(5, 6, 8); // ten past
|
|
||||||
strip.setSegment(4, 24, 27); //past
|
|
||||||
}
|
|
||||||
else if (minute <= 19)
|
|
||||||
{
|
|
||||||
strip.setSegment(5, 8, 12); // quarter past
|
|
||||||
strip.setSegment(3, 0, 0); //minutes
|
|
||||||
strip.setSegment(4, 24, 27); //past
|
|
||||||
}
|
|
||||||
else if (minute <= 24)
|
|
||||||
{
|
|
||||||
strip.setSegment(5, 12, 16); // twenty past
|
|
||||||
strip.setSegment(4, 24, 27); //past
|
|
||||||
}
|
|
||||||
else if (minute <= 29)
|
|
||||||
{
|
|
||||||
strip.setSegment(5, 12, 18); // twenty-five past
|
|
||||||
strip.setSegment(4, 24, 27); //past
|
|
||||||
}
|
|
||||||
else if (minute <= 34)
|
|
||||||
{
|
|
||||||
strip.setSegment(5, 3, 6); // half past
|
|
||||||
strip.setSegment(3, 0, 0); //minutes
|
|
||||||
strip.setSegment(4, 24, 27); //past
|
|
||||||
}
|
|
||||||
else if (minute <= 39)
|
|
||||||
{
|
|
||||||
strip.setSegment(5, 12, 18); // twenty-five to
|
|
||||||
strip.setSegment(6, 22, 24); //to
|
|
||||||
}
|
|
||||||
else if (minute <= 44)
|
|
||||||
{
|
|
||||||
strip.setSegment(5, 12, 16); // twenty to
|
|
||||||
strip.setSegment(6, 22, 24); //to
|
|
||||||
}
|
|
||||||
else if (minute <= 49)
|
|
||||||
{
|
|
||||||
strip.setSegment(5, 8, 12); // quarter to
|
|
||||||
strip.setSegment(3, 0, 0); //minutes
|
|
||||||
strip.setSegment(6, 22, 24); //to
|
|
||||||
}
|
|
||||||
else if (minute <= 54)
|
|
||||||
{
|
|
||||||
strip.setSegment(5, 6, 8); // ten to
|
|
||||||
strip.setSegment(6, 22, 24); //to
|
|
||||||
}
|
|
||||||
else if (minute <= 59)
|
|
||||||
{
|
|
||||||
strip.setSegment(5, 16, 18); // five to
|
|
||||||
strip.setSegment(6, 22, 24); //to
|
|
||||||
}
|
|
||||||
|
|
||||||
//hours
|
|
||||||
if (hour > 23)
|
|
||||||
return;
|
|
||||||
if (isToHour)
|
|
||||||
hour++;
|
|
||||||
if (hour > 12)
|
|
||||||
hour -= 12;
|
|
||||||
if (hour == 0)
|
|
||||||
hour = 12;
|
|
||||||
|
|
||||||
switch (hour)
|
|
||||||
{
|
|
||||||
case 1:
|
|
||||||
strip.setSegment(7, 27, 29);
|
|
||||||
break; //one
|
|
||||||
case 2:
|
|
||||||
strip.setSegment(7, 35, 37);
|
|
||||||
break; //two
|
|
||||||
case 3:
|
|
||||||
strip.setSegment(7, 29, 32);
|
|
||||||
break; //three
|
|
||||||
case 4:
|
|
||||||
strip.setSegment(7, 32, 35);
|
|
||||||
break; //four
|
|
||||||
case 5:
|
|
||||||
strip.setSegment(7, 37, 40);
|
|
||||||
break; //five
|
|
||||||
case 6:
|
|
||||||
strip.setSegment(7, 43, 45);
|
|
||||||
break; //six
|
|
||||||
case 7:
|
|
||||||
strip.setSegment(7, 40, 43);
|
|
||||||
break; //seven
|
|
||||||
case 8:
|
|
||||||
strip.setSegment(7, 45, 48);
|
|
||||||
break; //eight
|
|
||||||
case 9:
|
|
||||||
strip.setSegment(7, 48, 50);
|
|
||||||
break; //nine
|
|
||||||
case 10:
|
|
||||||
strip.setSegment(7, 54, 56);
|
|
||||||
break; //ten
|
|
||||||
case 11:
|
|
||||||
strip.setSegment(7, 50, 54);
|
|
||||||
break; //eleven
|
|
||||||
case 12:
|
|
||||||
strip.setSegment(7, 56, 60);
|
|
||||||
break; //twelve
|
|
||||||
}
|
|
||||||
|
|
||||||
selectWordSegments(true);
|
|
||||||
applyMacro(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void timeOfDay() {
|
|
||||||
// NOT USED: use timed macros instead
|
|
||||||
//Used to set brightness dependant of time of day - lights dimmed at night
|
|
||||||
|
|
||||||
//monday to thursday and sunday
|
|
||||||
|
|
||||||
if ((weekday(localTime) == 6) | (weekday(localTime) == 7)) {
|
|
||||||
if (hour(localTime) > 0 | hour(localTime) < 8) {
|
|
||||||
strip.setBrightness(nightBrightness);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
strip.setBrightness(dayBrightness);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (hour(localTime) < 6 | hour(localTime) >= 22) {
|
|
||||||
strip.setBrightness(nightBrightness);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
strip.setBrightness(dayBrightness);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//loop. You can use "if (WLED_CONNECTED)" to check for successful connection
|
|
||||||
void userLoop()
|
|
||||||
{
|
|
||||||
if (minute(localTime) != minuteLast)
|
|
||||||
{
|
|
||||||
updateLocalTime();
|
|
||||||
//timeOfDay();
|
|
||||||
minuteLast = minute(localTime);
|
|
||||||
displayTime(hour(localTime), minute(localTime));
|
|
||||||
if (minute(localTime) == 0){
|
|
||||||
hourChime();
|
|
||||||
}
|
|
||||||
if (minute(localTime) == 1){
|
|
||||||
//turn off background segment;
|
|
||||||
strip.getSegment(0).setOption(2, false);
|
|
||||||
//applyPreset(255);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
1544
wled00/FX.cpp
1544
wled00/FX.cpp
File diff suppressed because it is too large
Load Diff
155
wled00/FX.h
155
wled00/FX.h
@ -16,6 +16,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "const.h"
|
#include "const.h"
|
||||||
|
#include "bus_manager.h"
|
||||||
|
|
||||||
#define FASTLED_INTERNAL //remove annoying pragma messages
|
#define FASTLED_INTERNAL //remove annoying pragma messages
|
||||||
#define USE_GET_MILLISECOND_TIMER
|
#define USE_GET_MILLISECOND_TIMER
|
||||||
@ -42,6 +43,9 @@
|
|||||||
#define RGBW32(r,g,b,w) (uint32_t((byte(w) << 24) | (byte(r) << 16) | (byte(g) << 8) | (byte(b))))
|
#define RGBW32(r,g,b,w) (uint32_t((byte(w) << 24) | (byte(r) << 16) | (byte(g) << 8) | (byte(b))))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
extern bool realtimeRespectLedMaps; // used in getMappedPixelIndex()
|
||||||
|
extern byte realtimeMode; // used in getMappedPixelIndex()
|
||||||
|
|
||||||
/* Not used in all effects yet */
|
/* Not used in all effects yet */
|
||||||
#define WLED_FPS 42
|
#define WLED_FPS 42
|
||||||
#define FRAMETIME_FIXED (1000/WLED_FPS)
|
#define FRAMETIME_FIXED (1000/WLED_FPS)
|
||||||
@ -88,11 +92,11 @@
|
|||||||
#define NUM_COLORS 3 /* number of colors per segment */
|
#define NUM_COLORS 3 /* number of colors per segment */
|
||||||
#define SEGMENT strip._segments[strip.getCurrSegmentId()]
|
#define SEGMENT strip._segments[strip.getCurrSegmentId()]
|
||||||
#define SEGENV strip._segments[strip.getCurrSegmentId()]
|
#define SEGENV strip._segments[strip.getCurrSegmentId()]
|
||||||
//#define SEGCOLOR(x) strip._segments[strip.getCurrSegmentId()].currentColor(x, strip._segments[strip.getCurrSegmentId()].colors[x])
|
#define SEGCOLOR(x) Segment::getCurrentColor(x)
|
||||||
//#define SEGLEN strip._segments[strip.getCurrSegmentId()].virtualLength()
|
|
||||||
#define SEGCOLOR(x) strip.segColor(x) /* saves us a few kbytes of code */
|
|
||||||
#define SEGPALETTE Segment::getCurrentPalette()
|
#define SEGPALETTE Segment::getCurrentPalette()
|
||||||
#define SEGLEN strip._virtualSegmentLength /* saves us a few kbytes of code */
|
#define SEGLEN Segment::vLength()
|
||||||
|
#define SEG_W Segment::vWidth()
|
||||||
|
#define SEG_H Segment::vHeight()
|
||||||
#define SPEED_FORMULA_L (5U + (50U*(255U - SEGMENT.speed))/SEGLEN)
|
#define SPEED_FORMULA_L (5U + (50U*(255U - SEGMENT.speed))/SEGLEN)
|
||||||
|
|
||||||
// some common colors
|
// some common colors
|
||||||
@ -204,7 +208,7 @@
|
|||||||
#define FX_MODE_COLORTWINKLE 74
|
#define FX_MODE_COLORTWINKLE 74
|
||||||
#define FX_MODE_LAKE 75
|
#define FX_MODE_LAKE 75
|
||||||
#define FX_MODE_METEOR 76
|
#define FX_MODE_METEOR 76
|
||||||
#define FX_MODE_METEOR_SMOOTH 77
|
//#define FX_MODE_METEOR_SMOOTH 77 // merged with meteor
|
||||||
#define FX_MODE_RAILWAY 78
|
#define FX_MODE_RAILWAY 78
|
||||||
#define FX_MODE_RIPPLE 79
|
#define FX_MODE_RIPPLE 79
|
||||||
#define FX_MODE_TWINKLEFOX 80
|
#define FX_MODE_TWINKLEFOX 80
|
||||||
@ -398,7 +402,7 @@ typedef struct Segment {
|
|||||||
uint32_t _stepT;
|
uint32_t _stepT;
|
||||||
uint32_t _callT;
|
uint32_t _callT;
|
||||||
uint8_t *_dataT;
|
uint8_t *_dataT;
|
||||||
uint16_t _dataLenT;
|
unsigned _dataLenT;
|
||||||
TemporarySegmentData()
|
TemporarySegmentData()
|
||||||
: _dataT(nullptr) // just in case...
|
: _dataT(nullptr) // just in case...
|
||||||
, _dataLenT(0)
|
, _dataLenT(0)
|
||||||
@ -416,10 +420,14 @@ typedef struct Segment {
|
|||||||
uint8_t _reserved : 4;
|
uint8_t _reserved : 4;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
uint16_t _dataLen;
|
uint8_t _default_palette; // palette number that gets assigned to pal0
|
||||||
static uint16_t _usedSegmentData;
|
unsigned _dataLen;
|
||||||
|
static unsigned _usedSegmentData;
|
||||||
// perhaps this should be per segment, not static
|
static uint8_t _segBri; // brightness of segment for current effect
|
||||||
|
static unsigned _vLength; // 1D dimension used for current effect
|
||||||
|
static unsigned _vWidth, _vHeight; // 2D dimensions used for current effect
|
||||||
|
static uint32_t _currentColors[NUM_COLORS]; // colors used for current effect
|
||||||
|
static bool _colorScaled; // color has been scaled prior to setPixelColor() call
|
||||||
static CRGBPalette16 _currentPalette; // palette used for current effect (includes transition, used in color_from_palette())
|
static CRGBPalette16 _currentPalette; // palette used for current effect (includes transition, used in color_from_palette())
|
||||||
static CRGBPalette16 _randomPalette; // actual random palette
|
static CRGBPalette16 _randomPalette; // actual random palette
|
||||||
static CRGBPalette16 _newRandomPalette; // target random palette
|
static CRGBPalette16 _newRandomPalette; // target random palette
|
||||||
@ -452,6 +460,8 @@ typedef struct Segment {
|
|||||||
{}
|
{}
|
||||||
} *_t;
|
} *_t;
|
||||||
|
|
||||||
|
[[gnu::hot]] void _setPixelColorXY_raw(int& x, int& y, uint32_t& col); // set pixel without mapping (internal use only)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Segment(uint16_t sStart=0, uint16_t sStop=30) :
|
Segment(uint16_t sStart=0, uint16_t sStop=30) :
|
||||||
@ -484,6 +494,7 @@ typedef struct Segment {
|
|||||||
aux1(0),
|
aux1(0),
|
||||||
data(nullptr),
|
data(nullptr),
|
||||||
_capabilities(0),
|
_capabilities(0),
|
||||||
|
_default_palette(0),
|
||||||
_dataLen(0),
|
_dataLen(0),
|
||||||
_t(nullptr)
|
_t(nullptr)
|
||||||
{
|
{
|
||||||
@ -532,23 +543,30 @@ typedef struct Segment {
|
|||||||
inline uint16_t length() const { return width() * height(); } // segment length (count) in physical pixels
|
inline uint16_t length() const { return width() * height(); } // segment length (count) in physical pixels
|
||||||
inline uint16_t groupLength() const { return grouping + spacing; }
|
inline uint16_t groupLength() const { return grouping + spacing; }
|
||||||
inline uint8_t getLightCapabilities() const { return _capabilities; }
|
inline uint8_t getLightCapabilities() const { return _capabilities; }
|
||||||
|
inline void deactivate() { setGeometry(0,0); }
|
||||||
|
|
||||||
inline static uint16_t getUsedSegmentData() { return _usedSegmentData; }
|
inline static unsigned getUsedSegmentData() { return Segment::_usedSegmentData; }
|
||||||
inline static void addUsedSegmentData(int len) { _usedSegmentData += len; }
|
inline static void addUsedSegmentData(int len) { Segment::_usedSegmentData += len; }
|
||||||
#ifndef WLED_DISABLE_MODE_BLEND
|
#ifndef WLED_DISABLE_MODE_BLEND
|
||||||
inline static void modeBlend(bool blend) { _modeBlend = blend; }
|
inline static void modeBlend(bool blend) { _modeBlend = blend; }
|
||||||
#endif
|
#endif
|
||||||
static void handleRandomPalette();
|
inline static unsigned vLength() { return Segment::_vLength; }
|
||||||
|
inline static unsigned vWidth() { return Segment::_vWidth; }
|
||||||
|
inline static unsigned vHeight() { return Segment::_vHeight; }
|
||||||
|
inline static uint32_t getCurrentColor(unsigned i) { return Segment::_currentColors[i]; } // { return i < 3 ? Segment::_currentColors[i] : 0; }
|
||||||
inline static const CRGBPalette16 &getCurrentPalette() { return Segment::_currentPalette; }
|
inline static const CRGBPalette16 &getCurrentPalette() { return Segment::_currentPalette; }
|
||||||
|
inline static uint8_t getCurrentBrightness() { return Segment::_segBri; }
|
||||||
|
static void handleRandomPalette();
|
||||||
|
|
||||||
void setUp(uint16_t i1, uint16_t i2, uint8_t grp=1, uint8_t spc=0, uint16_t ofs=UINT16_MAX, uint16_t i1Y=0, uint16_t i2Y=1);
|
void beginDraw(); // set up parameters for current effect
|
||||||
|
void setGeometry(uint16_t i1, uint16_t i2, uint8_t grp=1, uint8_t spc=0, uint16_t ofs=UINT16_MAX, uint16_t i1Y=0, uint16_t i2Y=1, uint8_t m12=0);
|
||||||
Segment &setColor(uint8_t slot, uint32_t c);
|
Segment &setColor(uint8_t slot, uint32_t c);
|
||||||
Segment &setCCT(uint16_t k);
|
Segment &setCCT(uint16_t k);
|
||||||
Segment &setOpacity(uint8_t o);
|
Segment &setOpacity(uint8_t o);
|
||||||
Segment &setOption(uint8_t n, bool val);
|
Segment &setOption(uint8_t n, bool val);
|
||||||
Segment &setMode(uint8_t fx, bool loadDefaults = false);
|
Segment &setMode(uint8_t fx, bool loadDefaults = false);
|
||||||
Segment &setPalette(uint8_t pal);
|
Segment &setPalette(uint8_t pal);
|
||||||
uint8_t differs(Segment& b) const;
|
uint8_t differs(const Segment& b) const;
|
||||||
void refreshLightCapabilities();
|
void refreshLightCapabilities();
|
||||||
|
|
||||||
// runtime data functions
|
// runtime data functions
|
||||||
@ -578,7 +596,6 @@ typedef struct Segment {
|
|||||||
uint8_t currentMode() const; // currently active effect/mode (while in transition)
|
uint8_t currentMode() const; // currently active effect/mode (while in transition)
|
||||||
[[gnu::hot]] uint32_t currentColor(uint8_t slot) const; // currently active segment color (blended while in transition)
|
[[gnu::hot]] uint32_t currentColor(uint8_t slot) const; // currently active segment color (blended while in transition)
|
||||||
CRGBPalette16 &loadPalette(CRGBPalette16 &tgt, uint8_t pal);
|
CRGBPalette16 &loadPalette(CRGBPalette16 &tgt, uint8_t pal);
|
||||||
void setCurrentPalette();
|
|
||||||
|
|
||||||
// 1D strip
|
// 1D strip
|
||||||
[[gnu::hot]] uint16_t virtualLength() const;
|
[[gnu::hot]] uint16_t virtualLength() const;
|
||||||
@ -599,21 +616,19 @@ typedef struct Segment {
|
|||||||
void fadeToBlackBy(uint8_t fadeBy);
|
void fadeToBlackBy(uint8_t fadeBy);
|
||||||
inline void blendPixelColor(int n, uint32_t color, uint8_t blend) { setPixelColor(n, color_blend(getPixelColor(n), color, blend)); }
|
inline void blendPixelColor(int n, uint32_t color, uint8_t blend) { setPixelColor(n, color_blend(getPixelColor(n), color, blend)); }
|
||||||
inline void blendPixelColor(int n, CRGB c, uint8_t blend) { blendPixelColor(n, RGBW32(c.r,c.g,c.b,0), blend); }
|
inline void blendPixelColor(int n, CRGB c, uint8_t blend) { blendPixelColor(n, RGBW32(c.r,c.g,c.b,0), blend); }
|
||||||
inline void addPixelColor(int n, uint32_t color, bool fast = false) { setPixelColor(n, color_add(getPixelColor(n), color, fast)); }
|
inline void addPixelColor(int n, uint32_t color, bool preserveCR = true) { setPixelColor(n, color_add(getPixelColor(n), color, preserveCR)); }
|
||||||
inline void addPixelColor(int n, byte r, byte g, byte b, byte w = 0, bool fast = false) { addPixelColor(n, RGBW32(r,g,b,w), fast); }
|
inline void addPixelColor(int n, byte r, byte g, byte b, byte w = 0, bool preserveCR = true) { addPixelColor(n, RGBW32(r,g,b,w), preserveCR); }
|
||||||
inline void addPixelColor(int n, CRGB c, bool fast = false) { addPixelColor(n, RGBW32(c.r,c.g,c.b,0), fast); }
|
inline void addPixelColor(int n, CRGB c, bool preserveCR = true) { addPixelColor(n, RGBW32(c.r,c.g,c.b,0), preserveCR); }
|
||||||
inline void fadePixelColor(uint16_t n, uint8_t fade) { setPixelColor(n, color_fade(getPixelColor(n), fade, true)); }
|
inline void fadePixelColor(uint16_t n, uint8_t fade) { setPixelColor(n, color_fade(getPixelColor(n), fade, true)); }
|
||||||
[[gnu::hot]] uint32_t color_from_palette(uint16_t, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri = 255) const;
|
[[gnu::hot]] uint32_t color_from_palette(uint16_t, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri = 255) const;
|
||||||
[[gnu::hot]] uint32_t color_wheel(uint8_t pos) const;
|
[[gnu::hot]] uint32_t color_wheel(uint8_t pos) const;
|
||||||
|
|
||||||
// 2D Blur: shortcuts for bluring columns or rows only (50% faster than full 2D blur)
|
// 2D Blur: shortcuts for bluring columns or rows only (50% faster than full 2D blur)
|
||||||
inline void blurCols(fract8 blur_amount, bool smear = false) { // blur all columns
|
inline void blurCols(fract8 blur_amount, bool smear = false) { // blur all columns
|
||||||
const unsigned cols = virtualWidth();
|
blur2D(0, blur_amount, smear);
|
||||||
for (unsigned k = 0; k < cols; k++) blurCol(k, blur_amount, smear);
|
|
||||||
}
|
}
|
||||||
inline void blurRows(fract8 blur_amount, bool smear = false) { // blur all rows
|
inline void blurRows(fract8 blur_amount, bool smear = false) { // blur all rows
|
||||||
const unsigned rows = virtualHeight();
|
blur2D(blur_amount, 0, smear);
|
||||||
for ( unsigned i = 0; i < rows; i++) blurRow(i, blur_amount, smear);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2D matrix
|
// 2D matrix
|
||||||
@ -642,31 +657,28 @@ typedef struct Segment {
|
|||||||
// 2D support functions
|
// 2D support functions
|
||||||
inline void blendPixelColorXY(uint16_t x, uint16_t y, uint32_t color, uint8_t blend) { setPixelColorXY(x, y, color_blend(getPixelColorXY(x,y), color, blend)); }
|
inline void blendPixelColorXY(uint16_t x, uint16_t y, uint32_t color, uint8_t blend) { setPixelColorXY(x, y, color_blend(getPixelColorXY(x,y), color, blend)); }
|
||||||
inline void blendPixelColorXY(uint16_t x, uint16_t y, CRGB c, uint8_t blend) { blendPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), blend); }
|
inline void blendPixelColorXY(uint16_t x, uint16_t y, CRGB c, uint8_t blend) { blendPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), blend); }
|
||||||
inline void addPixelColorXY(int x, int y, uint32_t color, bool fast = false) { setPixelColorXY(x, y, color_add(getPixelColorXY(x,y), color, fast)); }
|
inline void addPixelColorXY(int x, int y, uint32_t color, bool preserveCR = true) { setPixelColorXY(x, y, color_add(getPixelColorXY(x,y), color, preserveCR)); }
|
||||||
inline void addPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0, bool fast = false) { addPixelColorXY(x, y, RGBW32(r,g,b,w), fast); }
|
inline void addPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0, bool preserveCR = true) { addPixelColorXY(x, y, RGBW32(r,g,b,w), preserveCR); }
|
||||||
inline void addPixelColorXY(int x, int y, CRGB c, bool fast = false) { addPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), fast); }
|
inline void addPixelColorXY(int x, int y, CRGB c, bool preserveCR = true) { addPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), preserveCR); }
|
||||||
inline void fadePixelColorXY(uint16_t x, uint16_t y, uint8_t fade) { setPixelColorXY(x, y, color_fade(getPixelColorXY(x,y), fade, true)); }
|
inline void fadePixelColorXY(uint16_t x, uint16_t y, uint8_t fade) { setPixelColorXY(x, y, color_fade(getPixelColorXY(x,y), fade, true)); }
|
||||||
void box_blur(unsigned r = 1U, bool smear = false); // 2D box blur
|
//void box_blur(unsigned r = 1U, bool smear = false); // 2D box blur
|
||||||
void blur2D(uint8_t blur_amount, bool smear = false);
|
void blur2D(uint8_t blur_x, uint8_t blur_y, bool smear = false);
|
||||||
void blurRow(uint32_t row, fract8 blur_amount, bool smear = false);
|
void moveX(int delta, bool wrap = false);
|
||||||
void blurCol(uint32_t col, fract8 blur_amount, bool smear = false);
|
void moveY(int delta, bool wrap = false);
|
||||||
void moveX(int8_t delta, bool wrap = false);
|
void move(unsigned dir, unsigned delta, bool wrap = false);
|
||||||
void moveY(int8_t delta, bool wrap = false);
|
|
||||||
void move(uint8_t dir, uint8_t delta, bool wrap = false);
|
|
||||||
void drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t c, bool soft = false);
|
void drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t c, bool soft = false);
|
||||||
inline void drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c, bool soft = false) { drawCircle(cx, cy, radius, RGBW32(c.r,c.g,c.b,0), soft); }
|
inline void drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c, bool soft = false) { drawCircle(cx, cy, radius, RGBW32(c.r,c.g,c.b,0), soft); }
|
||||||
void fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t c, bool soft = false);
|
void fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t c, bool soft = false);
|
||||||
inline void fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c, bool soft = false) { fillCircle(cx, cy, radius, RGBW32(c.r,c.g,c.b,0), soft); }
|
inline void fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c, bool soft = false) { fillCircle(cx, cy, radius, RGBW32(c.r,c.g,c.b,0), soft); }
|
||||||
void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c, bool soft = false);
|
void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c, bool soft = false);
|
||||||
inline void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, CRGB c, bool soft = false) { drawLine(x0, y0, x1, y1, RGBW32(c.r,c.g,c.b,0), soft); } // automatic inline
|
inline void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, CRGB c, bool soft = false) { drawLine(x0, y0, x1, y1, RGBW32(c.r,c.g,c.b,0), soft); } // automatic inline
|
||||||
void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t col2 = 0, int8_t rotate = 0);
|
void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t col2 = 0, int8_t rotate = 0, bool usePalGrad = false);
|
||||||
inline 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
|
inline 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
|
||||||
inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB c, CRGB c2, int8_t rotate = 0) { drawCharacter(chr, x, y, w, h, RGBW32(c.r,c.g,c.b,0), RGBW32(c2.r,c2.g,c2.b,0), rotate); } // automatic inline
|
inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB c, CRGB c2, int8_t rotate = 0, bool usePalGrad = false) { drawCharacter(chr, x, y, w, h, RGBW32(c.r,c.g,c.b,0), RGBW32(c2.r,c2.g,c2.b,0), rotate, usePalGrad); } // automatic inline
|
||||||
void wu_pixel(uint32_t x, uint32_t y, CRGB c);
|
void wu_pixel(uint32_t x, uint32_t y, CRGB c);
|
||||||
inline void blur2d(fract8 blur_amount) { blur(blur_amount); }
|
|
||||||
inline void fill_solid(CRGB c) { fill(RGBW32(c.r,c.g,c.b,0)); }
|
inline void fill_solid(CRGB c) { fill(RGBW32(c.r,c.g,c.b,0)); }
|
||||||
#else
|
#else
|
||||||
inline uint16_t XY(uint16_t x, uint16_t y) { return x; }
|
inline uint16_t XY(int x, int y) { return x; }
|
||||||
inline void setPixelColorXY(int x, int y, uint32_t c) { setPixelColor(x, c); }
|
inline void setPixelColorXY(int x, int y, uint32_t c) { setPixelColor(x, c); }
|
||||||
inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c) { setPixelColor(int(x), c); }
|
inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c) { setPixelColor(int(x), c); }
|
||||||
inline void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { setPixelColor(x, RGBW32(r,g,b,w)); }
|
inline void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { setPixelColor(x, RGBW32(r,g,b,w)); }
|
||||||
@ -680,16 +692,16 @@ typedef struct Segment {
|
|||||||
inline uint32_t getPixelColorXY(int x, int y) { return getPixelColor(x); }
|
inline uint32_t getPixelColorXY(int x, int y) { return getPixelColor(x); }
|
||||||
inline void blendPixelColorXY(uint16_t x, uint16_t y, uint32_t c, uint8_t blend) { blendPixelColor(x, c, blend); }
|
inline void blendPixelColorXY(uint16_t x, uint16_t y, uint32_t c, uint8_t blend) { blendPixelColor(x, c, blend); }
|
||||||
inline void blendPixelColorXY(uint16_t x, uint16_t y, CRGB c, uint8_t blend) { blendPixelColor(x, RGBW32(c.r,c.g,c.b,0), blend); }
|
inline void blendPixelColorXY(uint16_t x, uint16_t y, CRGB c, uint8_t blend) { blendPixelColor(x, RGBW32(c.r,c.g,c.b,0), blend); }
|
||||||
inline void addPixelColorXY(int x, int y, uint32_t color, bool fast = false) { addPixelColor(x, color, fast); }
|
inline void addPixelColorXY(int x, int y, uint32_t color, bool saturate = false) { addPixelColor(x, color, saturate); }
|
||||||
inline void addPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0, bool fast = false) { addPixelColor(x, RGBW32(r,g,b,w), fast); }
|
inline void addPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0, bool saturate = false) { addPixelColor(x, RGBW32(r,g,b,w), saturate); }
|
||||||
inline void addPixelColorXY(int x, int y, CRGB c, bool fast = false) { addPixelColor(x, RGBW32(c.r,c.g,c.b,0), fast); }
|
inline void addPixelColorXY(int x, int y, CRGB c, bool saturate = false) { addPixelColor(x, RGBW32(c.r,c.g,c.b,0), saturate); }
|
||||||
inline void fadePixelColorXY(uint16_t x, uint16_t y, uint8_t fade) { fadePixelColor(x, fade); }
|
inline void fadePixelColorXY(uint16_t x, uint16_t y, uint8_t fade) { fadePixelColor(x, fade); }
|
||||||
inline void box_blur(unsigned i, bool vertical, fract8 blur_amount) {}
|
//inline void box_blur(unsigned i, bool vertical, fract8 blur_amount) {}
|
||||||
inline void blur2D(uint8_t blur_amount, bool smear = false) {}
|
inline void blur2D(uint8_t blur_x, uint8_t blur_y, bool smear = false) {}
|
||||||
inline void blurRow(uint32_t row, fract8 blur_amount, bool smear = false) {}
|
inline void blurRow(int row, fract8 blur_amount, bool smear = false) {}
|
||||||
inline void blurCol(uint32_t col, fract8 blur_amount, bool smear = false) {}
|
inline void blurCol(int col, fract8 blur_amount, bool smear = false) {}
|
||||||
inline void moveX(int8_t delta, bool wrap = false) {}
|
inline void moveX(int delta, bool wrap = false) {}
|
||||||
inline void moveY(int8_t delta, bool wrap = false) {}
|
inline void moveY(int delta, bool wrap = false) {}
|
||||||
inline void move(uint8_t dir, uint8_t delta, bool wrap = false) {}
|
inline void move(uint8_t dir, uint8_t delta, bool wrap = false) {}
|
||||||
inline void drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t c, bool soft = false) {}
|
inline void drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t c, bool soft = false) {}
|
||||||
inline void drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c, bool soft = false) {}
|
inline void drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c, bool soft = false) {}
|
||||||
@ -697,9 +709,9 @@ typedef struct Segment {
|
|||||||
inline void fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c, bool soft = false) {}
|
inline void fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c, bool soft = false) {}
|
||||||
inline void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c, bool soft = false) {}
|
inline void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c, bool soft = false) {}
|
||||||
inline void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, CRGB c, bool soft = false) {}
|
inline void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, CRGB c, bool soft = false) {}
|
||||||
inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t = 0, int8_t = 0) {}
|
inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t = 0, int8_t = 0, bool = false) {}
|
||||||
inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB color) {}
|
inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB color) {}
|
||||||
inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB c, CRGB c2, int8_t rotate = 0) {}
|
inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB c, CRGB c2, int8_t rotate = 0, bool usePalGrad = false) {}
|
||||||
inline void wu_pixel(uint32_t x, uint32_t y, CRGB c) {}
|
inline void wu_pixel(uint32_t x, uint32_t y, CRGB c) {}
|
||||||
#endif
|
#endif
|
||||||
} segment;
|
} segment;
|
||||||
@ -737,9 +749,6 @@ class WS2812FX { // 96 bytes
|
|||||||
#endif
|
#endif
|
||||||
correctWB(false),
|
correctWB(false),
|
||||||
cctFromRgb(false),
|
cctFromRgb(false),
|
||||||
// semi-private (just obscured) used in effect functions through macros
|
|
||||||
_colors_t{0,0,0},
|
|
||||||
_virtualSegmentLength(0),
|
|
||||||
// true private variables
|
// true private variables
|
||||||
_suspend(false),
|
_suspend(false),
|
||||||
_length(DEFAULT_LED_COUNT),
|
_length(DEFAULT_LED_COUNT),
|
||||||
@ -787,26 +796,22 @@ class WS2812FX { // 96 bytes
|
|||||||
#endif
|
#endif
|
||||||
finalizeInit(), // initialises strip components
|
finalizeInit(), // initialises strip components
|
||||||
service(), // executes effect functions when due and calls strip.show()
|
service(), // executes effect functions when due and calls strip.show()
|
||||||
setMode(uint8_t segid, uint8_t m), // sets effect/mode for given segment (high level API)
|
|
||||||
setColor(uint8_t slot, uint32_t c), // sets color (in slot) for given segment (high level API)
|
|
||||||
setCCT(uint16_t k), // sets global CCT (either in relative 0-255 value or in K)
|
setCCT(uint16_t k), // sets global CCT (either in relative 0-255 value or in K)
|
||||||
setBrightness(uint8_t b, bool direct = false), // sets strip brightness
|
setBrightness(uint8_t b, bool direct = false), // sets strip brightness
|
||||||
setRange(uint16_t i, uint16_t i2, uint32_t col), // used for clock overlay
|
setRange(uint16_t i, uint16_t i2, uint32_t col), // used for clock overlay
|
||||||
purgeSegments(), // removes inactive segments from RAM (may incure penalty and memory fragmentation but reduces vector footprint)
|
purgeSegments(), // removes inactive segments from RAM (may incure penalty and memory fragmentation but reduces vector footprint)
|
||||||
setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t grouping = 1, uint8_t spacing = 0, uint16_t offset = UINT16_MAX, uint16_t startY=0, uint16_t stopY=1),
|
setMainSegmentId(unsigned n = 0),
|
||||||
setMainSegmentId(uint8_t n),
|
|
||||||
resetSegments(), // marks all segments for reset
|
resetSegments(), // marks all segments for reset
|
||||||
makeAutoSegments(bool forceReset = false), // will create segments based on configured outputs
|
makeAutoSegments(bool forceReset = false), // will create segments based on configured outputs
|
||||||
fixInvalidSegments(), // fixes incorrect segment configuration
|
fixInvalidSegments(), // fixes incorrect segment configuration
|
||||||
setPixelColor(unsigned n, uint32_t c), // paints absolute strip pixel with index n and color c
|
setPixelColor(unsigned n, uint32_t c), // paints absolute strip pixel with index n and color c
|
||||||
show(), // initiates LED output
|
show(), // initiates LED output
|
||||||
setTargetFps(uint8_t fps),
|
setTargetFps(unsigned fps),
|
||||||
setupEffectData(); // add default effects to the list; defined in FX.cpp
|
setupEffectData(); // add default effects to the list; defined in FX.cpp
|
||||||
|
|
||||||
inline void resetTimebase() { timebase = 0UL - millis(); }
|
inline void resetTimebase() { timebase = 0UL - millis(); }
|
||||||
inline void restartRuntime() { for (Segment &seg : _segments) { seg.markForReset().resetIfRequired(); } }
|
inline void restartRuntime() { for (Segment &seg : _segments) { seg.markForReset().resetIfRequired(); } }
|
||||||
inline void setTransitionMode(bool t) { for (Segment &seg : _segments) seg.startTransition(t ? _transitionDur : 0); }
|
inline void setTransitionMode(bool t) { for (Segment &seg : _segments) seg.startTransition(t ? _transitionDur : 0); }
|
||||||
inline void setColor(uint8_t slot, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0) { setColor(slot, RGBW32(r,g,b,w)); }
|
|
||||||
inline void setPixelColor(unsigned n, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0) { setPixelColor(n, RGBW32(r,g,b,w)); }
|
inline void setPixelColor(unsigned n, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0) { setPixelColor(n, RGBW32(r,g,b,w)); }
|
||||||
inline void setPixelColor(unsigned n, CRGB c) { setPixelColor(n, c.red, c.green, c.blue); }
|
inline void setPixelColor(unsigned n, CRGB c) { setPixelColor(n, c.red, c.green, c.blue); }
|
||||||
inline void fill(uint32_t c) { for (unsigned i = 0; i < getLengthTotal(); i++) setPixelColor(i, c); } // fill whole strip with color (inline)
|
inline void fill(uint32_t c) { for (unsigned i = 0; i < getLengthTotal(); i++) setPixelColor(i, c); } // fill whole strip with color (inline)
|
||||||
@ -822,9 +827,9 @@ class WS2812FX { // 96 bytes
|
|||||||
checkSegmentAlignment(),
|
checkSegmentAlignment(),
|
||||||
hasRGBWBus() const,
|
hasRGBWBus() const,
|
||||||
hasCCTBus() const,
|
hasCCTBus() const,
|
||||||
isUpdating() const, // return true if the strip is being sent pixel updates
|
deserializeMap(unsigned n = 0);
|
||||||
deserializeMap(uint8_t n=0);
|
|
||||||
|
|
||||||
|
inline bool isUpdating() const { return !BusManager::canAllShow(); } // return true if the strip is being sent pixel updates
|
||||||
inline bool isServicing() const { return _isServicing; } // returns true if strip.service() is executing
|
inline bool isServicing() const { return _isServicing; } // returns true if strip.service() is executing
|
||||||
inline bool hasWhiteChannel() const { return _hasWhiteChannel; } // returns true if strip contains separate white chanel
|
inline bool hasWhiteChannel() const { return _hasWhiteChannel; } // returns true if strip contains separate white chanel
|
||||||
inline bool isOffRefreshRequired() const { return _isOffRefreshRequired; } // returns true if strip requires regular updates (i.e. TM1814 chipset)
|
inline bool isOffRefreshRequired() const { return _isOffRefreshRequired; } // returns true if strip requires regular updates (i.e. TM1814 chipset)
|
||||||
@ -841,7 +846,7 @@ class WS2812FX { // 96 bytes
|
|||||||
addEffect(uint8_t id, mode_ptr mode_fn, const char *mode_name); // add effect to the list; defined in FX.cpp;
|
addEffect(uint8_t id, mode_ptr mode_fn, const char *mode_name); // add effect to the list; defined in FX.cpp;
|
||||||
|
|
||||||
inline uint8_t getBrightness() const { return _brightness; } // returns current strip brightness
|
inline uint8_t getBrightness() const { return _brightness; } // returns current strip brightness
|
||||||
inline uint8_t getMaxSegments() const { return MAX_NUM_SEGMENTS; } // returns maximum number of supported segments (fixed value)
|
inline static constexpr unsigned getMaxSegments() { return MAX_NUM_SEGMENTS; } // returns maximum number of supported segments (fixed value)
|
||||||
inline uint8_t getSegmentsNum() const { return _segments.size(); } // returns currently present segments
|
inline uint8_t getSegmentsNum() const { return _segments.size(); } // returns currently present segments
|
||||||
inline uint8_t getCurrSegmentId() const { return _segment_index; } // returns current segment index (only valid while strip.isServicing())
|
inline uint8_t getCurrSegmentId() const { return _segment_index; } // returns current segment index (only valid while strip.isServicing())
|
||||||
inline uint8_t getMainSegmentId() const { return _mainSegment; } // returns main segment index
|
inline uint8_t getMainSegmentId() const { return _mainSegment; } // returns main segment index
|
||||||
@ -851,28 +856,27 @@ class WS2812FX { // 96 bytes
|
|||||||
|
|
||||||
uint16_t
|
uint16_t
|
||||||
getLengthPhysical() const,
|
getLengthPhysical() const,
|
||||||
getLengthTotal() const, // will include virtual/nonexistent pixels in matrix
|
getLengthTotal() const; // will include virtual/nonexistent pixels in matrix
|
||||||
getFps() const,
|
|
||||||
getMappedPixelIndex(uint16_t index) const;
|
|
||||||
|
|
||||||
|
inline uint16_t getFps() const { return (millis() - _lastShow > 2000) ? 0 : (FPS_MULTIPLIER * _cumulativeFps) >> FPS_CALC_SHIFT; } // Returns the refresh rate of the LED strip (_cumulativeFps is stored in fixed point)
|
||||||
inline uint16_t getFrameTime() const { return _frametime; } // returns amount of time a frame should take (in ms)
|
inline uint16_t getFrameTime() const { return _frametime; } // returns amount of time a frame should take (in ms)
|
||||||
inline uint16_t getMinShowDelay() const { return MIN_FRAME_DELAY; } // returns minimum amount of time strip.service() can be delayed (constant)
|
inline uint16_t getMinShowDelay() const { return MIN_FRAME_DELAY; } // returns minimum amount of time strip.service() can be delayed (constant)
|
||||||
inline uint16_t getLength() const { return _length; } // returns actual amount of LEDs on a strip (2D matrix may have less LEDs than W*H)
|
inline uint16_t getLength() const { return _length; } // returns actual amount of LEDs on a strip (2D matrix may have less LEDs than W*H)
|
||||||
inline uint16_t getTransition() const { return _transitionDur; } // returns currently set transition time (in ms)
|
inline uint16_t getTransition() const { return _transitionDur; } // returns currently set transition time (in ms)
|
||||||
|
inline uint16_t getMappedPixelIndex(uint16_t index) const { // convert logical address to physical
|
||||||
|
if (index < customMappingSize && (realtimeMode == REALTIME_MODE_INACTIVE || realtimeRespectLedMaps)) index = customMappingTable[index];
|
||||||
|
return index;
|
||||||
|
};
|
||||||
|
|
||||||
unsigned long now, timebase;
|
unsigned long now, timebase;
|
||||||
uint32_t getPixelColor(unsigned) const;
|
uint32_t getPixelColor(unsigned) const;
|
||||||
|
|
||||||
inline uint32_t getLastShow() const { return _lastShow; } // returns millis() timestamp of last strip.show() call
|
inline uint32_t getLastShow() const { return _lastShow; } // returns millis() timestamp of last strip.show() call
|
||||||
inline uint32_t segColor(uint8_t i) const { return _colors_t[i]; } // returns currently valid color (for slot i) AKA SEGCOLOR(); may be blended between two colors while in transition
|
|
||||||
|
|
||||||
const char *
|
const char *getModeData(unsigned id = 0) const { return (id && id < _modeCount) ? _modeData[id] : PSTR("Solid"); }
|
||||||
getModeData(uint8_t id = 0) const { return (id && id<_modeCount) ? _modeData[id] : PSTR("Solid"); }
|
inline const char **getModeDataSrc() { return &(_modeData[0]); } // vectors use arrays for underlying data
|
||||||
|
|
||||||
const char **
|
Segment& getSegment(unsigned id);
|
||||||
getModeDataSrc() { return &(_modeData[0]); } // vectors use arrays for underlying data
|
|
||||||
|
|
||||||
Segment& getSegment(uint8_t id);
|
|
||||||
inline Segment& getFirstSelectedSeg() { return _segments[getFirstSelectedSegId()]; } // returns reference to first segment that is "selected"
|
inline Segment& getFirstSelectedSeg() { return _segments[getFirstSelectedSegId()]; } // returns reference to first segment that is "selected"
|
||||||
inline Segment& getMainSegment() { return _segments[getMainSegmentId()]; } // returns reference to main segment
|
inline Segment& getMainSegment() { return _segments[getMainSegmentId()]; } // returns reference to main segment
|
||||||
inline Segment* getSegments() { return &(_segments[0]); } // returns pointer to segment vector structure (warning: use carefully)
|
inline Segment* getSegments() { return &(_segments[0]); } // returns pointer to segment vector structure (warning: use carefully)
|
||||||
@ -931,11 +935,6 @@ class WS2812FX { // 96 bytes
|
|||||||
bool cctFromRgb : 1;
|
bool cctFromRgb : 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
// using public variables to reduce code size increase due to inline function getSegment() (with bounds checking)
|
|
||||||
// and color transitions
|
|
||||||
uint32_t _colors_t[3]; // color used for effect (includes transition)
|
|
||||||
uint16_t _virtualSegmentLength;
|
|
||||||
|
|
||||||
std::vector<segment> _segments;
|
std::vector<segment> _segments;
|
||||||
friend class Segment;
|
friend class Segment;
|
||||||
|
|
||||||
|
@ -148,57 +148,68 @@ void WS2812FX::setUpMatrix() {
|
|||||||
// XY(x,y) - gets pixel index within current segment (often used to reference leds[] array element)
|
// XY(x,y) - gets pixel index within current segment (often used to reference leds[] array element)
|
||||||
uint16_t IRAM_ATTR_YN Segment::XY(int x, int y)
|
uint16_t IRAM_ATTR_YN Segment::XY(int x, int y)
|
||||||
{
|
{
|
||||||
unsigned width = virtualWidth(); // segment width in logical pixels (can be 0 if segment is inactive)
|
const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive)
|
||||||
unsigned height = virtualHeight(); // segment height in logical pixels (is always >= 1)
|
const int vH = vHeight(); // segment height in logical pixels (is always >= 1)
|
||||||
return isActive() ? (x%width) + (y%height) * width : 0;
|
return isActive() ? (x%vW) + (y%vH) * vW : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// raw setColor function without checks (checks are done in setPixelColorXY())
|
||||||
|
void IRAM_ATTR_YN Segment::_setPixelColorXY_raw(int& x, int& y, uint32_t& col)
|
||||||
|
{
|
||||||
|
const int baseX = start + x;
|
||||||
|
const int baseY = startY + y;
|
||||||
|
#ifndef WLED_DISABLE_MODE_BLEND
|
||||||
|
// if blending modes, blend with underlying pixel
|
||||||
|
if (_modeBlend) col = color_blend16(strip.getPixelColorXY(baseX, baseY), col, 0xFFFFU - progress());
|
||||||
|
#endif
|
||||||
|
strip.setPixelColorXY(baseX, baseY, col);
|
||||||
|
|
||||||
|
// Apply mirroring
|
||||||
|
if (mirror || mirror_y) {
|
||||||
|
auto setMirroredPixel = [&](int mx, int my) {
|
||||||
|
strip.setPixelColorXY(mx, my, col);
|
||||||
|
};
|
||||||
|
|
||||||
|
const int mirrorX = start + width() - x - 1;
|
||||||
|
const int mirrorY = startY + height() - y - 1;
|
||||||
|
|
||||||
|
if (mirror) setMirroredPixel(transpose ? baseX : mirrorX, transpose ? mirrorY : baseY);
|
||||||
|
if (mirror_y) setMirroredPixel(transpose ? mirrorX : baseX, transpose ? baseY : mirrorY);
|
||||||
|
if (mirror && mirror_y) setMirroredPixel(mirrorX, mirrorY);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col)
|
void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col)
|
||||||
{
|
{
|
||||||
if (!isActive()) return; // not active
|
if (!isActive()) return; // not active
|
||||||
if ((unsigned)x >= virtualWidth() || (unsigned)y >= virtualHeight() || x<0 || y<0) return; // if pixel would fall out of virtual segment just exit
|
|
||||||
|
|
||||||
uint8_t _bri_t = currentBri();
|
const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive)
|
||||||
if (_bri_t < 255) {
|
const int vH = vHeight(); // segment height in logical pixels (is always >= 1)
|
||||||
col = color_fade(col, _bri_t);
|
// negative values of x & y cast into unsigend will become very large values and will therefore be greater than vW/vH
|
||||||
}
|
if (unsigned(x) >= unsigned(vW) || unsigned(y) >= unsigned(vH)) return; // if pixel would fall out of virtual segment just exit
|
||||||
|
|
||||||
if (reverse ) x = virtualWidth() - x - 1;
|
// if color is unscaled
|
||||||
if (reverse_y) y = virtualHeight() - y - 1;
|
if (!_colorScaled) col = color_fade(col, _segBri);
|
||||||
|
|
||||||
|
if (reverse ) x = vW - x - 1;
|
||||||
|
if (reverse_y) y = vH - y - 1;
|
||||||
if (transpose) { std::swap(x,y); } // swap X & Y if segment transposed
|
if (transpose) { std::swap(x,y); } // swap X & Y if segment transposed
|
||||||
|
unsigned groupLen = groupLength();
|
||||||
|
|
||||||
x *= groupLength(); // expand to physical pixels
|
if (groupLen > 1) {
|
||||||
y *= groupLength(); // expand to physical pixels
|
int W = width();
|
||||||
|
int H = height();
|
||||||
int W = width();
|
x *= groupLen; // expand to physical pixels
|
||||||
int H = height();
|
y *= groupLen; // expand to physical pixels
|
||||||
if (x >= W || y >= H) return; // if pixel would fall out of segment just exit
|
const int maxY = std::min(y + grouping, H);
|
||||||
|
const int maxX = std::min(x + grouping, W);
|
||||||
uint32_t tmpCol = col;
|
for (int yY = y; yY < maxY; yY++) {
|
||||||
for (int j = 0; j < grouping; j++) { // groupping vertically
|
for (int xX = x; xX < maxX; xX++) {
|
||||||
for (int g = 0; g < grouping; g++) { // groupping horizontally
|
_setPixelColorXY_raw(xX, yY, col);
|
||||||
int xX = (x+g), yY = (y+j);
|
|
||||||
if (xX >= W || yY >= H) continue; // we have reached one dimension's end
|
|
||||||
|
|
||||||
#ifndef WLED_DISABLE_MODE_BLEND
|
|
||||||
// if blending modes, blend with underlying pixel
|
|
||||||
if (_modeBlend) tmpCol = color_blend(strip.getPixelColorXY(start + xX, startY + yY), col, 0xFFFFU - progress(), true);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
strip.setPixelColorXY(start + xX, startY + yY, tmpCol);
|
|
||||||
|
|
||||||
if (mirror) { //set the corresponding horizontally mirrored pixel
|
|
||||||
if (transpose) strip.setPixelColorXY(start + xX, startY + height() - yY - 1, tmpCol);
|
|
||||||
else strip.setPixelColorXY(start + width() - xX - 1, startY + yY, tmpCol);
|
|
||||||
}
|
|
||||||
if (mirror_y) { //set the corresponding vertically mirrored pixel
|
|
||||||
if (transpose) strip.setPixelColorXY(start + width() - xX - 1, startY + yY, tmpCol);
|
|
||||||
else strip.setPixelColorXY(start + xX, startY + height() - yY - 1, tmpCol);
|
|
||||||
}
|
|
||||||
if (mirror_y && mirror) { //set the corresponding vertically AND horizontally mirrored pixel
|
|
||||||
strip.setPixelColorXY(start + width() - xX - 1, startY + height() - yY - 1, tmpCol);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
_setPixelColorXY_raw(x, y, col);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,11 +220,8 @@ void Segment::setPixelColorXY(float x, float y, uint32_t col, bool aa)
|
|||||||
if (!isActive()) return; // not active
|
if (!isActive()) return; // not active
|
||||||
if (x<0.0f || x>1.0f || y<0.0f || y>1.0f) return; // not normalized
|
if (x<0.0f || x>1.0f || y<0.0f || y>1.0f) return; // not normalized
|
||||||
|
|
||||||
const unsigned cols = virtualWidth();
|
float fX = x * (vWidth()-1);
|
||||||
const unsigned rows = virtualHeight();
|
float fY = y * (vHeight()-1);
|
||||||
|
|
||||||
float fX = x * (cols-1);
|
|
||||||
float fY = y * (rows-1);
|
|
||||||
if (aa) {
|
if (aa) {
|
||||||
unsigned xL = roundf(fX-0.49f);
|
unsigned xL = roundf(fX-0.49f);
|
||||||
unsigned xR = roundf(fX+0.49f);
|
unsigned xR = roundf(fX+0.49f);
|
||||||
@ -251,9 +259,11 @@ void Segment::setPixelColorXY(float x, float y, uint32_t col, bool aa)
|
|||||||
// returns RGBW values of pixel
|
// returns RGBW values of pixel
|
||||||
uint32_t IRAM_ATTR_YN Segment::getPixelColorXY(int x, int y) const {
|
uint32_t IRAM_ATTR_YN Segment::getPixelColorXY(int x, int y) const {
|
||||||
if (!isActive()) return 0; // not active
|
if (!isActive()) return 0; // not active
|
||||||
if ((unsigned)x >= virtualWidth() || (unsigned)y >= virtualHeight() || x<0 || y<0) return 0; // if pixel would fall out of virtual segment just exit
|
const int vW = vWidth();
|
||||||
if (reverse ) x = virtualWidth() - x - 1;
|
const int vH = vHeight();
|
||||||
if (reverse_y) y = virtualHeight() - y - 1;
|
if (unsigned(x) >= unsigned(vW) || unsigned(y) >= unsigned(vH)) return 0; // if pixel would fall out of virtual segment just exit
|
||||||
|
if (reverse ) x = vW - x - 1;
|
||||||
|
if (reverse_y) y = vH - y - 1;
|
||||||
if (transpose) { std::swap(x,y); } // swap X & Y if segment transposed
|
if (transpose) { std::swap(x,y); } // swap X & Y if segment transposed
|
||||||
x *= groupLength(); // expand to physical pixels
|
x *= groupLength(); // expand to physical pixels
|
||||||
y *= groupLength(); // expand to physical pixels
|
y *= groupLength(); // expand to physical pixels
|
||||||
@ -261,128 +271,69 @@ uint32_t IRAM_ATTR_YN Segment::getPixelColorXY(int x, int y) const {
|
|||||||
return strip.getPixelColorXY(start + x, startY + y);
|
return strip.getPixelColorXY(start + x, startY + y);
|
||||||
}
|
}
|
||||||
|
|
||||||
// blurRow: perform a blur on a row of a rectangular matrix
|
// 2D blurring, can be asymmetrical
|
||||||
void Segment::blurRow(uint32_t row, fract8 blur_amount, bool smear){
|
void Segment::blur2D(uint8_t blur_x, uint8_t blur_y, bool smear) {
|
||||||
if (!isActive() || blur_amount == 0) return; // not active
|
if (!isActive()) return; // not active
|
||||||
const unsigned cols = virtualWidth();
|
const unsigned cols = vWidth();
|
||||||
const unsigned rows = virtualHeight();
|
const unsigned rows = vHeight();
|
||||||
|
|
||||||
if (row >= rows) return;
|
|
||||||
// blur one row
|
|
||||||
uint8_t keep = smear ? 255 : 255 - blur_amount;
|
|
||||||
uint8_t seep = blur_amount >> 1;
|
|
||||||
uint32_t carryover = BLACK;
|
|
||||||
uint32_t lastnew;
|
uint32_t lastnew;
|
||||||
uint32_t last;
|
uint32_t last;
|
||||||
uint32_t curnew = BLACK;
|
if (blur_x) {
|
||||||
for (unsigned x = 0; x < cols; x++) {
|
const uint8_t keepx = smear ? 255 : 255 - blur_x;
|
||||||
uint32_t cur = getPixelColorXY(x, row);
|
const uint8_t seepx = blur_x >> 1;
|
||||||
uint32_t part = color_fade(cur, seep);
|
for (unsigned row = 0; row < rows; row++) { // blur rows (x direction)
|
||||||
curnew = color_fade(cur, keep);
|
uint32_t carryover = BLACK;
|
||||||
if (x > 0) {
|
uint32_t curnew = BLACK;
|
||||||
if (carryover)
|
for (unsigned x = 0; x < cols; x++) {
|
||||||
curnew = color_add(curnew, carryover, true);
|
uint32_t cur = getPixelColorXY(x, row);
|
||||||
uint32_t prev = color_add(lastnew, part, true);
|
uint32_t part = color_fade(cur, seepx);
|
||||||
if (last != prev) // optimization: only set pixel if color has changed
|
curnew = color_fade(cur, keepx);
|
||||||
setPixelColorXY(x - 1, row, prev);
|
if (x > 0) {
|
||||||
} else // first pixel
|
if (carryover) curnew = color_add(curnew, carryover);
|
||||||
setPixelColorXY(x, row, curnew);
|
uint32_t prev = color_add(lastnew, part);
|
||||||
lastnew = curnew;
|
// optimization: only set pixel if color has changed
|
||||||
last = cur; // save original value for comparison on next iteration
|
if (last != prev) setPixelColorXY(x - 1, row, prev);
|
||||||
carryover = part;
|
} else setPixelColorXY(x, row, curnew); // first pixel
|
||||||
}
|
lastnew = curnew;
|
||||||
setPixelColorXY(cols-1, row, curnew); // set last pixel
|
last = cur; // save original value for comparison on next iteration
|
||||||
}
|
carryover = part;
|
||||||
|
}
|
||||||
// blurCol: perform a blur on a column of a rectangular matrix
|
setPixelColorXY(cols-1, row, curnew); // set last pixel
|
||||||
void Segment::blurCol(uint32_t col, fract8 blur_amount, bool smear) {
|
|
||||||
if (!isActive() || blur_amount == 0) return; // not active
|
|
||||||
const unsigned cols = virtualWidth();
|
|
||||||
const unsigned rows = virtualHeight();
|
|
||||||
|
|
||||||
if (col >= cols) return;
|
|
||||||
// blur one column
|
|
||||||
uint8_t keep = smear ? 255 : 255 - blur_amount;
|
|
||||||
uint8_t seep = blur_amount >> 1;
|
|
||||||
uint32_t carryover = BLACK;
|
|
||||||
uint32_t lastnew;
|
|
||||||
uint32_t last;
|
|
||||||
uint32_t curnew = BLACK;
|
|
||||||
for (unsigned y = 0; y < rows; y++) {
|
|
||||||
uint32_t cur = getPixelColorXY(col, y);
|
|
||||||
uint32_t part = color_fade(cur, seep);
|
|
||||||
curnew = color_fade(cur, keep);
|
|
||||||
if (y > 0) {
|
|
||||||
if (carryover)
|
|
||||||
curnew = color_add(curnew, carryover, true);
|
|
||||||
uint32_t prev = color_add(lastnew, part, true);
|
|
||||||
if (last != prev) // optimization: only set pixel if color has changed
|
|
||||||
setPixelColorXY(col, y - 1, prev);
|
|
||||||
} else // first pixel
|
|
||||||
setPixelColorXY(col, y, curnew);
|
|
||||||
lastnew = curnew;
|
|
||||||
last = cur; //save original value for comparison on next iteration
|
|
||||||
carryover = part;
|
|
||||||
}
|
|
||||||
setPixelColorXY(col, rows - 1, curnew);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Segment::blur2D(uint8_t blur_amount, bool smear) {
|
|
||||||
if (!isActive() || blur_amount == 0) return; // not active
|
|
||||||
const unsigned cols = virtualWidth();
|
|
||||||
const unsigned rows = virtualHeight();
|
|
||||||
|
|
||||||
const uint8_t keep = smear ? 255 : 255 - blur_amount;
|
|
||||||
const uint8_t seep = blur_amount >> (1 + smear);
|
|
||||||
uint32_t lastnew;
|
|
||||||
uint32_t last;
|
|
||||||
for (unsigned row = 0; row < rows; row++) {
|
|
||||||
uint32_t carryover = BLACK;
|
|
||||||
uint32_t curnew = BLACK;
|
|
||||||
for (unsigned x = 0; x < cols; x++) {
|
|
||||||
uint32_t cur = getPixelColorXY(x, row);
|
|
||||||
uint32_t part = color_fade(cur, seep);
|
|
||||||
curnew = color_fade(cur, keep);
|
|
||||||
if (x > 0) {
|
|
||||||
if (carryover) curnew = color_add(curnew, carryover, true);
|
|
||||||
uint32_t prev = color_add(lastnew, part, true);
|
|
||||||
// optimization: only set pixel if color has changed
|
|
||||||
if (last != prev) setPixelColorXY(x - 1, row, prev);
|
|
||||||
} else setPixelColorXY(x, row, curnew); // first pixel
|
|
||||||
lastnew = curnew;
|
|
||||||
last = cur; // save original value for comparison on next iteration
|
|
||||||
carryover = part;
|
|
||||||
}
|
}
|
||||||
setPixelColorXY(cols-1, row, curnew); // set last pixel
|
|
||||||
}
|
}
|
||||||
for (unsigned col = 0; col < cols; col++) {
|
if (blur_y) {
|
||||||
uint32_t carryover = BLACK;
|
const uint8_t keepy = smear ? 255 : 255 - blur_y;
|
||||||
uint32_t curnew = BLACK;
|
const uint8_t seepy = blur_y >> 1;
|
||||||
for (unsigned y = 0; y < rows; y++) {
|
for (unsigned col = 0; col < cols; col++) {
|
||||||
uint32_t cur = getPixelColorXY(col, y);
|
uint32_t carryover = BLACK;
|
||||||
uint32_t part = color_fade(cur, seep);
|
uint32_t curnew = BLACK;
|
||||||
curnew = color_fade(cur, keep);
|
for (unsigned y = 0; y < rows; y++) {
|
||||||
if (y > 0) {
|
uint32_t cur = getPixelColorXY(col, y);
|
||||||
if (carryover) curnew = color_add(curnew, carryover, true);
|
uint32_t part = color_fade(cur, seepy);
|
||||||
uint32_t prev = color_add(lastnew, part, true);
|
curnew = color_fade(cur, keepy);
|
||||||
// optimization: only set pixel if color has changed
|
if (y > 0) {
|
||||||
if (last != prev) setPixelColorXY(col, y - 1, prev);
|
if (carryover) curnew = color_add(curnew, carryover);
|
||||||
} else setPixelColorXY(col, y, curnew); // first pixel
|
uint32_t prev = color_add(lastnew, part);
|
||||||
lastnew = curnew;
|
// optimization: only set pixel if color has changed
|
||||||
last = cur; //save original value for comparison on next iteration
|
if (last != prev) setPixelColorXY(col, y - 1, prev);
|
||||||
carryover = part;
|
} else setPixelColorXY(col, y, curnew); // first pixel
|
||||||
|
lastnew = curnew;
|
||||||
|
last = cur; //save original value for comparison on next iteration
|
||||||
|
carryover = part;
|
||||||
|
}
|
||||||
|
setPixelColorXY(col, rows - 1, curnew);
|
||||||
}
|
}
|
||||||
setPixelColorXY(col, rows - 1, curnew);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
// 2D Box blur
|
// 2D Box blur
|
||||||
void Segment::box_blur(unsigned radius, bool smear) {
|
void Segment::box_blur(unsigned radius, bool smear) {
|
||||||
if (!isActive() || radius == 0) return; // not active
|
if (!isActive() || radius == 0) return; // not active
|
||||||
if (radius > 3) radius = 3;
|
if (radius > 3) radius = 3;
|
||||||
const unsigned d = (1 + 2*radius) * (1 + 2*radius); // averaging divisor
|
const unsigned d = (1 + 2*radius) * (1 + 2*radius); // averaging divisor
|
||||||
const unsigned cols = virtualWidth();
|
const unsigned cols = vWidth();
|
||||||
const unsigned rows = virtualHeight();
|
const unsigned rows = vHeight();
|
||||||
uint16_t *tmpRSum = new uint16_t[cols*rows];
|
uint16_t *tmpRSum = new uint16_t[cols*rows];
|
||||||
uint16_t *tmpGSum = new uint16_t[cols*rows];
|
uint16_t *tmpGSum = new uint16_t[cols*rows];
|
||||||
uint16_t *tmpBSum = new uint16_t[cols*rows];
|
uint16_t *tmpBSum = new uint16_t[cols*rows];
|
||||||
@ -448,40 +399,56 @@ void Segment::box_blur(unsigned radius, bool smear) {
|
|||||||
delete[] tmpBSum;
|
delete[] tmpBSum;
|
||||||
delete[] tmpWSum;
|
delete[] tmpWSum;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
void Segment::moveX(int8_t delta, bool wrap) {
|
void Segment::moveX(int delta, bool wrap) {
|
||||||
if (!isActive()) return; // not active
|
if (!isActive() || !delta) return; // not active
|
||||||
const int cols = virtualWidth();
|
const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive)
|
||||||
const int rows = virtualHeight();
|
const int vH = vHeight(); // segment height in logical pixels (is always >= 1)
|
||||||
if (!delta || abs(delta) >= cols) return;
|
int absDelta = abs(delta);
|
||||||
uint32_t newPxCol[cols];
|
if (absDelta >= vW) return;
|
||||||
for (int y = 0; y < rows; y++) {
|
uint32_t newPxCol[vW];
|
||||||
if (delta > 0) {
|
int newDelta;
|
||||||
for (int x = 0; x < cols-delta; x++) newPxCol[x] = getPixelColorXY((x + delta), y);
|
int stop = vW;
|
||||||
for (int x = cols-delta; x < cols; x++) newPxCol[x] = getPixelColorXY(wrap ? (x + delta) - cols : x, y);
|
int start = 0;
|
||||||
} else {
|
if (wrap) newDelta = (delta + vW) % vW; // +cols in case delta < 0
|
||||||
for (int x = cols-1; x >= -delta; x--) newPxCol[x] = getPixelColorXY((x + delta), y);
|
else {
|
||||||
for (int x = -delta-1; x >= 0; x--) newPxCol[x] = getPixelColorXY(wrap ? (x + delta) + cols : x, y);
|
if (delta < 0) start = absDelta;
|
||||||
|
stop = vW - absDelta;
|
||||||
|
newDelta = delta > 0 ? delta : 0;
|
||||||
|
}
|
||||||
|
for (int y = 0; y < vH; y++) {
|
||||||
|
for (int x = 0; x < stop; x++) {
|
||||||
|
int srcX = x + newDelta;
|
||||||
|
if (wrap) srcX %= vW; // Wrap using modulo when `wrap` is true
|
||||||
|
newPxCol[x] = getPixelColorXY(srcX, y);
|
||||||
}
|
}
|
||||||
for (int x = 0; x < cols; x++) setPixelColorXY(x, y, newPxCol[x]);
|
for (int x = 0; x < stop; x++) setPixelColorXY(x + start, y, newPxCol[x]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Segment::moveY(int8_t delta, bool wrap) {
|
void Segment::moveY(int delta, bool wrap) {
|
||||||
if (!isActive()) return; // not active
|
if (!isActive() || !delta) return; // not active
|
||||||
const int cols = virtualWidth();
|
const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive)
|
||||||
const int rows = virtualHeight();
|
const int vH = vHeight(); // segment height in logical pixels (is always >= 1)
|
||||||
if (!delta || abs(delta) >= rows) return;
|
int absDelta = abs(delta);
|
||||||
uint32_t newPxCol[rows];
|
if (absDelta >= vH) return;
|
||||||
for (int x = 0; x < cols; x++) {
|
uint32_t newPxCol[vH];
|
||||||
if (delta > 0) {
|
int newDelta;
|
||||||
for (int y = 0; y < rows-delta; y++) newPxCol[y] = getPixelColorXY(x, (y + delta));
|
int stop = vH;
|
||||||
for (int y = rows-delta; y < rows; y++) newPxCol[y] = getPixelColorXY(x, wrap ? (y + delta) - rows : y);
|
int start = 0;
|
||||||
} else {
|
if (wrap) newDelta = (delta + vH) % vH; // +rows in case delta < 0
|
||||||
for (int y = rows-1; y >= -delta; y--) newPxCol[y] = getPixelColorXY(x, (y + delta));
|
else {
|
||||||
for (int y = -delta-1; y >= 0; y--) newPxCol[y] = getPixelColorXY(x, wrap ? (y + delta) + rows : y);
|
if (delta < 0) start = absDelta;
|
||||||
|
stop = vH - absDelta;
|
||||||
|
newDelta = delta > 0 ? delta : 0;
|
||||||
|
}
|
||||||
|
for (int x = 0; x < vW; x++) {
|
||||||
|
for (int y = 0; y < stop; y++) {
|
||||||
|
int srcY = y + newDelta;
|
||||||
|
if (wrap) srcY %= vH; // Wrap using modulo when `wrap` is true
|
||||||
|
newPxCol[y] = getPixelColorXY(x, srcY);
|
||||||
}
|
}
|
||||||
for (int y = 0; y < rows; y++) setPixelColorXY(x, y, newPxCol[y]);
|
for (int y = 0; y < stop; y++) setPixelColorXY(x, y + start, newPxCol[y]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -489,7 +456,7 @@ void Segment::moveY(int8_t delta, bool wrap) {
|
|||||||
// @param dir direction: 0=left, 1=left-up, 2=up, 3=right-up, 4=right, 5=right-down, 6=down, 7=left-down
|
// @param dir direction: 0=left, 1=left-up, 2=up, 3=right-up, 4=right, 5=right-down, 6=down, 7=left-down
|
||||||
// @param delta number of pixels to move
|
// @param delta number of pixels to move
|
||||||
// @param wrap around
|
// @param wrap around
|
||||||
void Segment::move(uint8_t dir, uint8_t delta, bool wrap) {
|
void Segment::move(unsigned dir, unsigned delta, bool wrap) {
|
||||||
if (delta==0) return;
|
if (delta==0) return;
|
||||||
switch (dir) {
|
switch (dir) {
|
||||||
case 0: moveX( delta, wrap); break;
|
case 0: moveX( delta, wrap); break;
|
||||||
@ -507,46 +474,49 @@ void Segment::drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t col,
|
|||||||
if (!isActive() || radius == 0) return; // not active
|
if (!isActive() || radius == 0) return; // not active
|
||||||
if (soft) {
|
if (soft) {
|
||||||
// Xiaolin Wu’s algorithm
|
// Xiaolin Wu’s algorithm
|
||||||
int rsq = radius*radius;
|
const int rsq = radius*radius;
|
||||||
int x = 0;
|
int x = 0;
|
||||||
int y = radius;
|
int y = radius;
|
||||||
unsigned oldFade = 0;
|
unsigned oldFade = 0;
|
||||||
while (x < y) {
|
while (x < y) {
|
||||||
float yf = sqrtf(float(rsq - x*x)); // needs to be floating point
|
float yf = sqrtf(float(rsq - x*x)); // needs to be floating point
|
||||||
unsigned fade = float(0xFFFF) * (ceilf(yf) - yf); // how much color to keep
|
uint8_t fade = float(0xFF) * (ceilf(yf) - yf); // how much color to keep
|
||||||
if (oldFade > fade) y--;
|
if (oldFade > fade) y--;
|
||||||
oldFade = fade;
|
oldFade = fade;
|
||||||
setPixelColorXY(cx+x, cy+y, color_blend(col, getPixelColorXY(cx+x, cy+y), fade, true));
|
int px, py;
|
||||||
setPixelColorXY(cx-x, cy+y, color_blend(col, getPixelColorXY(cx-x, cy+y), fade, true));
|
for (uint8_t i = 0; i < 16; i++) {
|
||||||
setPixelColorXY(cx+x, cy-y, color_blend(col, getPixelColorXY(cx+x, cy-y), fade, true));
|
int swaps = (i & 0x4 ? 1 : 0); // 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1
|
||||||
setPixelColorXY(cx-x, cy-y, color_blend(col, getPixelColorXY(cx-x, cy-y), fade, true));
|
int adj = (i < 8) ? 0 : 1; // 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1
|
||||||
setPixelColorXY(cx+y, cy+x, color_blend(col, getPixelColorXY(cx+y, cy+x), fade, true));
|
int dx = (i & 1) ? -1 : 1; // 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1
|
||||||
setPixelColorXY(cx-y, cy+x, color_blend(col, getPixelColorXY(cx-y, cy+x), fade, true));
|
int dy = (i & 2) ? -1 : 1; // 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1
|
||||||
setPixelColorXY(cx+y, cy-x, color_blend(col, getPixelColorXY(cx+y, cy-x), fade, true));
|
if (swaps) {
|
||||||
setPixelColorXY(cx-y, cy-x, color_blend(col, getPixelColorXY(cx-y, cy-x), fade, true));
|
px = cx + (y - adj) * dx;
|
||||||
setPixelColorXY(cx+x, cy+y-1, color_blend(getPixelColorXY(cx+x, cy+y-1), col, fade, true));
|
py = cy + x * dy;
|
||||||
setPixelColorXY(cx-x, cy+y-1, color_blend(getPixelColorXY(cx-x, cy+y-1), col, fade, true));
|
} else {
|
||||||
setPixelColorXY(cx+x, cy-y+1, color_blend(getPixelColorXY(cx+x, cy-y+1), col, fade, true));
|
px = cx + x * dx;
|
||||||
setPixelColorXY(cx-x, cy-y+1, color_blend(getPixelColorXY(cx-x, cy-y+1), col, fade, true));
|
py = cy + (y - adj) * dy;
|
||||||
setPixelColorXY(cx+y-1, cy+x, color_blend(getPixelColorXY(cx+y-1, cy+x), col, fade, true));
|
}
|
||||||
setPixelColorXY(cx-y+1, cy+x, color_blend(getPixelColorXY(cx-y+1, cy+x), col, fade, true));
|
uint32_t pixCol = getPixelColorXY(px, py);
|
||||||
setPixelColorXY(cx+y-1, cy-x, color_blend(getPixelColorXY(cx+y-1, cy-x), col, fade, true));
|
setPixelColorXY(px, py, adj ?
|
||||||
setPixelColorXY(cx-y+1, cy-x, color_blend(getPixelColorXY(cx-y+1, cy-x), col, fade, true));
|
color_blend(pixCol, col, fade) :
|
||||||
|
color_blend(col, pixCol, fade));
|
||||||
|
}
|
||||||
x++;
|
x++;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// pre-scale color for all pixels
|
||||||
|
col = color_fade(col, _segBri);
|
||||||
|
_colorScaled = true;
|
||||||
// Bresenham’s Algorithm
|
// Bresenham’s Algorithm
|
||||||
int d = 3 - (2*radius);
|
int d = 3 - (2*radius);
|
||||||
int y = radius, x = 0;
|
int y = radius, x = 0;
|
||||||
while (y >= x) {
|
while (y >= x) {
|
||||||
setPixelColorXY(cx+x, cy+y, col);
|
for (int i = 0; i < 4; i++) {
|
||||||
setPixelColorXY(cx-x, cy+y, col);
|
int dx = (i & 1) ? -x : x;
|
||||||
setPixelColorXY(cx+x, cy-y, col);
|
int dy = (i & 2) ? -y : y;
|
||||||
setPixelColorXY(cx-x, cy-y, col);
|
setPixelColorXY(cx + dx, cy + dy, col);
|
||||||
setPixelColorXY(cx+y, cy+x, col);
|
setPixelColorXY(cx + dy, cy + dx, col);
|
||||||
setPixelColorXY(cx-y, cy+x, col);
|
}
|
||||||
setPixelColorXY(cx+y, cy-x, col);
|
|
||||||
setPixelColorXY(cx-y, cy-x, col);
|
|
||||||
x++;
|
x++;
|
||||||
if (d > 0) {
|
if (d > 0) {
|
||||||
y--;
|
y--;
|
||||||
@ -555,33 +525,38 @@ void Segment::drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t col,
|
|||||||
d += 4 * x + 6;
|
d += 4 * x + 6;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_colorScaled = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// by stepko, taken from https://editor.soulmatelights.com/gallery/573-blobs
|
// by stepko, taken from https://editor.soulmatelights.com/gallery/573-blobs
|
||||||
void Segment::fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t col, bool soft) {
|
void Segment::fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t col, bool soft) {
|
||||||
if (!isActive() || radius == 0) return; // not active
|
if (!isActive() || radius == 0) return; // not active
|
||||||
|
const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive)
|
||||||
|
const int vH = vHeight(); // segment height in logical pixels (is always >= 1)
|
||||||
// draw soft bounding circle
|
// draw soft bounding circle
|
||||||
if (soft) drawCircle(cx, cy, radius, col, soft);
|
if (soft) drawCircle(cx, cy, radius, col, soft);
|
||||||
|
// pre-scale color for all pixels
|
||||||
|
col = color_fade(col, _segBri);
|
||||||
|
_colorScaled = true;
|
||||||
// fill it
|
// fill it
|
||||||
const int cols = virtualWidth();
|
|
||||||
const int rows = virtualHeight();
|
|
||||||
for (int y = -radius; y <= radius; y++) {
|
for (int y = -radius; y <= radius; y++) {
|
||||||
for (int x = -radius; x <= radius; x++) {
|
for (int x = -radius; x <= radius; x++) {
|
||||||
if (x * x + y * y <= radius * radius &&
|
if (x * x + y * y <= radius * radius &&
|
||||||
int(cx)+x>=0 && int(cy)+y>=0 &&
|
int(cx)+x >= 0 && int(cy)+y >= 0 &&
|
||||||
int(cx)+x<cols && int(cy)+y<rows)
|
int(cx)+x < vW && int(cy)+y < vH)
|
||||||
setPixelColorXY(cx + x, cy + y, col);
|
setPixelColorXY(cx + x, cy + y, col);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_colorScaled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//line function
|
//line function
|
||||||
void Segment::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c, bool soft) {
|
void Segment::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c, bool soft) {
|
||||||
if (!isActive()) return; // not active
|
if (!isActive()) return; // not active
|
||||||
const int cols = virtualWidth();
|
const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive)
|
||||||
const int rows = virtualHeight();
|
const int vH = vHeight(); // segment height in logical pixels (is always >= 1)
|
||||||
if (x0 >= cols || x1 >= cols || y0 >= rows || y1 >= rows) return;
|
if (x0 >= vW || x1 >= vW || y0 >= vH || y1 >= vH) return;
|
||||||
|
|
||||||
const int dx = abs(x1-x0), sx = x0<x1 ? 1 : -1; // x distance & step
|
const int dx = abs(x1-x0), sx = x0<x1 ? 1 : -1; // x distance & step
|
||||||
const int dy = abs(y1-y0), sy = y0<y1 ? 1 : -1; // y distance & step
|
const int dy = abs(y1-y0), sy = y0<y1 ? 1 : -1; // y distance & step
|
||||||
@ -608,17 +583,20 @@ void Segment::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint3
|
|||||||
float gradient = x1-x0 == 0 ? 1.0f : float(y1-y0) / float(x1-x0);
|
float gradient = x1-x0 == 0 ? 1.0f : float(y1-y0) / float(x1-x0);
|
||||||
float intersectY = y0;
|
float intersectY = y0;
|
||||||
for (int x = x0; x <= x1; x++) {
|
for (int x = x0; x <= x1; x++) {
|
||||||
unsigned keep = float(0xFFFF) * (intersectY-int(intersectY)); // how much color to keep
|
uint8_t keep = float(0xFF) * (intersectY-int(intersectY)); // how much color to keep
|
||||||
unsigned seep = 0xFFFF - keep; // how much background to keep
|
uint8_t seep = 0xFF - keep; // how much background to keep
|
||||||
int y = int(intersectY);
|
int y = int(intersectY);
|
||||||
if (steep) std::swap(x,y); // temporaryly swap if steep
|
if (steep) std::swap(x,y); // temporaryly swap if steep
|
||||||
// pixel coverage is determined by fractional part of y co-ordinate
|
// pixel coverage is determined by fractional part of y co-ordinate
|
||||||
setPixelColorXY(x, y, color_blend(c, getPixelColorXY(x, y), keep, true));
|
setPixelColorXY(x, y, color_blend(c, getPixelColorXY(x, y), keep));
|
||||||
setPixelColorXY(x+int(steep), y+int(!steep), color_blend(c, getPixelColorXY(x+int(steep), y+int(!steep)), seep, true));
|
setPixelColorXY(x+int(steep), y+int(!steep), color_blend(c, getPixelColorXY(x+int(steep), y+int(!steep)), seep));
|
||||||
intersectY += gradient;
|
intersectY += gradient;
|
||||||
if (steep) std::swap(x,y); // restore if steep
|
if (steep) std::swap(x,y); // restore if steep
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// pre-scale color for all pixels
|
||||||
|
c = color_fade(c, _segBri);
|
||||||
|
_colorScaled = true;
|
||||||
// Bresenham's algorithm
|
// Bresenham's algorithm
|
||||||
int err = (dx>dy ? dx : -dy)/2; // error direction
|
int err = (dx>dy ? dx : -dy)/2; // error direction
|
||||||
for (;;) {
|
for (;;) {
|
||||||
@ -628,6 +606,7 @@ void Segment::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint3
|
|||||||
if (e2 >-dx) { err -= dy; x0 += sx; }
|
if (e2 >-dx) { err -= dy; x0 += sx; }
|
||||||
if (e2 < dy) { err += dx; y0 += sy; }
|
if (e2 < dy) { err += dx; y0 += sy; }
|
||||||
}
|
}
|
||||||
|
_colorScaled = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -639,16 +618,15 @@ void Segment::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint3
|
|||||||
|
|
||||||
// draws a raster font character on canvas
|
// draws a raster font character on canvas
|
||||||
// only supports: 4x6=24, 5x8=40, 5x12=60, 6x8=48 and 7x9=63 fonts ATM
|
// 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, uint32_t col2, int8_t rotate) {
|
void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t col2, int8_t rotate, bool usePalGrad) {
|
||||||
if (!isActive()) return; // not active
|
if (!isActive()) return; // not active
|
||||||
if (chr < 32 || chr > 126) return; // only ASCII 32-126 supported
|
if (chr < 32 || chr > 126) return; // only ASCII 32-126 supported
|
||||||
chr -= 32; // align with font table entries
|
chr -= 32; // align with font table entries
|
||||||
const int cols = virtualWidth();
|
|
||||||
const int rows = virtualHeight();
|
|
||||||
const int font = w*h;
|
const int font = w*h;
|
||||||
|
|
||||||
CRGB col = CRGB(color);
|
CRGB col = CRGB(color);
|
||||||
CRGBPalette16 grad = CRGBPalette16(col, col2 ? CRGB(col2) : col);
|
CRGBPalette16 grad = CRGBPalette16(col, col2 ? CRGB(col2) : col);
|
||||||
|
if(usePalGrad) grad = SEGPALETTE; // selected palette as gradient
|
||||||
|
|
||||||
//if (w<5 || w>6 || h!=8) return;
|
//if (w<5 || w>6 || h!=8) return;
|
||||||
for (int i = 0; i<h; i++) { // character height
|
for (int i = 0; i<h; i++) { // character height
|
||||||
@ -661,7 +639,10 @@ void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w,
|
|||||||
case 60: bits = pgm_read_byte_near(&console_font_5x12[(chr * h) + i]); break; // 5x12 font
|
case 60: bits = pgm_read_byte_near(&console_font_5x12[(chr * h) + i]); break; // 5x12 font
|
||||||
default: return;
|
default: return;
|
||||||
}
|
}
|
||||||
col = ColorFromPalette(grad, (i+1)*255/h, 255, NOBLEND);
|
uint32_t c = ColorFromPaletteWLED(grad, (i+1)*255/h, 255, NOBLEND);
|
||||||
|
// pre-scale color for all pixels
|
||||||
|
c = color_fade(c, _segBri);
|
||||||
|
_colorScaled = true;
|
||||||
for (int j = 0; j<w; j++) { // character width
|
for (int j = 0; j<w; j++) { // character width
|
||||||
int x0, y0;
|
int x0, y0;
|
||||||
switch (rotate) {
|
switch (rotate) {
|
||||||
@ -671,11 +652,12 @@ void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w,
|
|||||||
case 1: x0 = x + i; y0 = y + j; break; // +90 deg
|
case 1: x0 = x + i; y0 = y + j; break; // +90 deg
|
||||||
default: x0 = x + (w-1) - j; y0 = y + i; break; // no rotation
|
default: x0 = x + (w-1) - j; y0 = y + i; break; // no rotation
|
||||||
}
|
}
|
||||||
if (x0 < 0 || x0 >= cols || y0 < 0 || y0 >= rows) continue; // drawing off-screen
|
if (x0 < 0 || x0 >= (int)vWidth() || y0 < 0 || y0 >= (int)vHeight()) continue; // drawing off-screen
|
||||||
if (((bits>>(j+(8-w))) & 0x01)) { // bit set
|
if (((bits>>(j+(8-w))) & 0x01)) { // bit set
|
||||||
setPixelColorXY(x0, y0, col);
|
setPixelColorXY(x0, y0, c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_colorScaled = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,10 +66,15 @@ static constexpr bool validatePinsAndTypes(const unsigned* types, unsigned numTy
|
|||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// Segment class implementation
|
// Segment class implementation
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
uint16_t Segment::_usedSegmentData = 0U; // amount of RAM all segments use for their data[]
|
unsigned Segment::_usedSegmentData = 0U; // amount of RAM all segments use for their data[]
|
||||||
uint16_t Segment::maxWidth = DEFAULT_LED_COUNT;
|
uint16_t Segment::maxWidth = DEFAULT_LED_COUNT;
|
||||||
uint16_t Segment::maxHeight = 1;
|
uint16_t Segment::maxHeight = 1;
|
||||||
|
unsigned Segment::_vLength = 0;
|
||||||
|
unsigned Segment::_vWidth = 0;
|
||||||
|
unsigned Segment::_vHeight = 0;
|
||||||
|
uint8_t Segment::_segBri = 0;
|
||||||
|
uint32_t Segment::_currentColors[NUM_COLORS] = {0,0,0};
|
||||||
|
bool Segment::_colorScaled = false;
|
||||||
CRGBPalette16 Segment::_currentPalette = CRGBPalette16(CRGB::Black);
|
CRGBPalette16 Segment::_currentPalette = CRGBPalette16(CRGB::Black);
|
||||||
CRGBPalette16 Segment::_randomPalette = generateRandomPalette(); // was CRGBPalette16(DEFAULT_COLOR);
|
CRGBPalette16 Segment::_randomPalette = generateRandomPalette(); // was CRGBPalette16(DEFAULT_COLOR);
|
||||||
CRGBPalette16 Segment::_newRandomPalette = generateRandomPalette(); // was CRGBPalette16(DEFAULT_COLOR);
|
CRGBPalette16 Segment::_newRandomPalette = generateRandomPalette(); // was CRGBPalette16(DEFAULT_COLOR);
|
||||||
@ -196,19 +201,7 @@ CRGBPalette16 &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) {
|
|||||||
if (pal < 245 && pal > GRADIENT_PALETTE_COUNT+13) pal = 0;
|
if (pal < 245 && pal > GRADIENT_PALETTE_COUNT+13) pal = 0;
|
||||||
if (pal > 245 && (strip.customPalettes.size() == 0 || 255U-pal > strip.customPalettes.size()-1)) pal = 0; // TODO remove strip dependency by moving customPalettes out of strip
|
if (pal > 245 && (strip.customPalettes.size() == 0 || 255U-pal > strip.customPalettes.size()-1)) pal = 0; // TODO remove strip dependency by moving customPalettes out of strip
|
||||||
//default palette. Differs depending on effect
|
//default palette. Differs depending on effect
|
||||||
if (pal == 0) switch (mode) {
|
if (pal == 0) pal = _default_palette; //load default palette set in FX _data, party colors as default
|
||||||
case FX_MODE_FIRE_2012 : pal = 35; break; // heat palette
|
|
||||||
case FX_MODE_COLORWAVES : pal = 26; break; // landscape 33
|
|
||||||
case FX_MODE_FILLNOISE8 : pal = 9; break; // ocean colors
|
|
||||||
case FX_MODE_NOISE16_1 : pal = 20; break; // Drywet
|
|
||||||
case FX_MODE_NOISE16_2 : pal = 43; break; // Blue cyan yellow
|
|
||||||
case FX_MODE_NOISE16_3 : pal = 35; break; // heat palette
|
|
||||||
case FX_MODE_NOISE16_4 : pal = 26; break; // landscape 33
|
|
||||||
case FX_MODE_GLITTER : pal = 11; break; // rainbow colors
|
|
||||||
case FX_MODE_SUNRISE : pal = 35; break; // heat palette
|
|
||||||
case FX_MODE_RAILWAY : pal = 3; break; // prim + sec
|
|
||||||
case FX_MODE_2DSOAP : pal = 11; break; // rainbow colors
|
|
||||||
}
|
|
||||||
switch (pal) {
|
switch (pal) {
|
||||||
case 0: //default palette. Exceptions for specific effects above
|
case 0: //default palette. Exceptions for specific effects above
|
||||||
targetPalette = PartyColors_p; break;
|
targetPalette = PartyColors_p; break;
|
||||||
@ -385,7 +378,7 @@ void Segment::restoreSegenv(tmpsegd_t &tmpSeg) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
uint8_t IRAM_ATTR Segment::currentBri(bool useCct) const {
|
uint8_t Segment::currentBri(bool useCct) const {
|
||||||
unsigned prog = progress();
|
unsigned prog = progress();
|
||||||
if (prog < 0xFFFFU) {
|
if (prog < 0xFFFFU) {
|
||||||
unsigned curBri = (useCct ? cct : (on ? opacity : 0)) * prog;
|
unsigned curBri = (useCct ? cct : (on ? opacity : 0)) * prog;
|
||||||
@ -403,16 +396,31 @@ uint8_t Segment::currentMode() const {
|
|||||||
return mode;
|
return mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t IRAM_ATTR_YN Segment::currentColor(uint8_t slot) const {
|
uint32_t Segment::currentColor(uint8_t slot) const {
|
||||||
if (slot >= NUM_COLORS) slot = 0;
|
if (slot >= NUM_COLORS) slot = 0;
|
||||||
#ifndef WLED_DISABLE_MODE_BLEND
|
#ifndef WLED_DISABLE_MODE_BLEND
|
||||||
return isInTransition() ? color_blend(_t->_segT._colorT[slot], colors[slot], progress(), true) : colors[slot];
|
return isInTransition() ? color_blend16(_t->_segT._colorT[slot], colors[slot], progress()) : colors[slot];
|
||||||
#else
|
#else
|
||||||
return isInTransition() ? color_blend(_t->_colorT[slot], colors[slot], progress(), true) : colors[slot];
|
return isInTransition() ? color_blend16(_t->_colorT[slot], colors[slot], progress()) : colors[slot];
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void Segment::setCurrentPalette() {
|
// pre-calculate drawing parameters for faster access (based on the idea from @softhack007 from MM fork)
|
||||||
|
void Segment::beginDraw() {
|
||||||
|
_vWidth = virtualWidth();
|
||||||
|
_vHeight = virtualHeight();
|
||||||
|
_vLength = virtualLength();
|
||||||
|
_segBri = currentBri();
|
||||||
|
// adjust gamma for effects
|
||||||
|
for (unsigned i = 0; i < NUM_COLORS; i++) {
|
||||||
|
#ifndef WLED_DISABLE_MODE_BLEND
|
||||||
|
uint32_t col = isInTransition() ? color_blend16(_t->_segT._colorT[i], colors[i], progress()) : colors[i];
|
||||||
|
#else
|
||||||
|
uint32_t col = isInTransition() ? color_blend16(_t->_colorT[i], colors[i], progress()) : colors[i];
|
||||||
|
#endif
|
||||||
|
_currentColors[i] = gamma32(col);
|
||||||
|
}
|
||||||
|
// load palette into _currentPalette
|
||||||
loadPalette(_currentPalette, palette);
|
loadPalette(_currentPalette, palette);
|
||||||
unsigned prog = progress();
|
unsigned prog = progress();
|
||||||
if (strip.paletteFade && prog < 0xFFFFU) {
|
if (strip.paletteFade && prog < 0xFFFFU) {
|
||||||
@ -444,8 +452,10 @@ void Segment::handleRandomPalette() {
|
|||||||
nblendPaletteTowardPalette(_randomPalette, _newRandomPalette, 48);
|
nblendPaletteTowardPalette(_randomPalette, _newRandomPalette, 48);
|
||||||
}
|
}
|
||||||
|
|
||||||
// segId is given when called from network callback, changes are queued if that segment is currently in its effect function
|
// sets Segment geometry (length or width/height and grouping, spacing and offset as well as 2D mapping)
|
||||||
void Segment::setUp(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, uint16_t ofs, uint16_t i1Y, uint16_t i2Y) {
|
// strip must be suspended (strip.suspend()) before calling this function
|
||||||
|
// this function may call fill() to clear pixels if spacing or mapping changed (which requires setting _vWidth, _vHeight, _vLength or beginDraw())
|
||||||
|
void Segment::setGeometry(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, uint16_t ofs, uint16_t i1Y, uint16_t i2Y, uint8_t m12) {
|
||||||
// return if neither bounds nor grouping have changed
|
// return if neither bounds nor grouping have changed
|
||||||
bool boundsUnchanged = (start == i1 && stop == i2);
|
bool boundsUnchanged = (start == i1 && stop == i2);
|
||||||
#ifndef WLED_DISABLE_2D
|
#ifndef WLED_DISABLE_2D
|
||||||
@ -453,11 +463,19 @@ void Segment::setUp(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, uint16_t
|
|||||||
#endif
|
#endif
|
||||||
if (boundsUnchanged
|
if (boundsUnchanged
|
||||||
&& (!grp || (grouping == grp && spacing == spc))
|
&& (!grp || (grouping == grp && spacing == spc))
|
||||||
&& (ofs == UINT16_MAX || ofs == offset)) return;
|
&& (ofs == UINT16_MAX || ofs == offset)
|
||||||
|
&& (m12 == map1D2D)
|
||||||
|
) return;
|
||||||
|
|
||||||
stateChanged = true; // send UDP/WS broadcast
|
stateChanged = true; // send UDP/WS broadcast
|
||||||
|
|
||||||
if (stop) fill(BLACK); // turn old segment range off (clears pixels if changing spacing)
|
if (stop || spc != spacing || m12 != map1D2D) {
|
||||||
|
_vWidth = virtualWidth();
|
||||||
|
_vHeight = virtualHeight();
|
||||||
|
_vLength = virtualLength();
|
||||||
|
_segBri = currentBri();
|
||||||
|
fill(BLACK); // turn old segment range off or clears pixels if changing spacing (requires _vWidth/_vHeight/_vLength/_segBri)
|
||||||
|
}
|
||||||
if (grp) { // prevent assignment of 0
|
if (grp) { // prevent assignment of 0
|
||||||
grouping = grp;
|
grouping = grp;
|
||||||
spacing = spc;
|
spacing = spc;
|
||||||
@ -466,6 +484,7 @@ void Segment::setUp(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, uint16_t
|
|||||||
spacing = 0;
|
spacing = 0;
|
||||||
}
|
}
|
||||||
if (ofs < UINT16_MAX) offset = ofs;
|
if (ofs < UINT16_MAX) offset = ofs;
|
||||||
|
map1D2D = constrain(m12, 0, 7);
|
||||||
|
|
||||||
DEBUG_PRINT(F("setUp segment: ")); DEBUG_PRINT(i1);
|
DEBUG_PRINT(F("setUp segment: ")); DEBUG_PRINT(i1);
|
||||||
DEBUG_PRINT(','); DEBUG_PRINT(i2);
|
DEBUG_PRINT(','); DEBUG_PRINT(i2);
|
||||||
@ -554,9 +573,9 @@ Segment &Segment::setMode(uint8_t fx, bool loadDefaults) {
|
|||||||
if (modeBlending) startTransition(strip.getTransition()); // set effect transitions
|
if (modeBlending) startTransition(strip.getTransition()); // set effect transitions
|
||||||
#endif
|
#endif
|
||||||
mode = fx;
|
mode = fx;
|
||||||
|
int sOpt;
|
||||||
// load default values from effect string
|
// load default values from effect string
|
||||||
if (loadDefaults) {
|
if (loadDefaults) {
|
||||||
int sOpt;
|
|
||||||
sOpt = extractModeDefaults(fx, "sx"); speed = (sOpt >= 0) ? sOpt : DEFAULT_SPEED;
|
sOpt = extractModeDefaults(fx, "sx"); speed = (sOpt >= 0) ? sOpt : DEFAULT_SPEED;
|
||||||
sOpt = extractModeDefaults(fx, "ix"); intensity = (sOpt >= 0) ? sOpt : DEFAULT_INTENSITY;
|
sOpt = extractModeDefaults(fx, "ix"); intensity = (sOpt >= 0) ? sOpt : DEFAULT_INTENSITY;
|
||||||
sOpt = extractModeDefaults(fx, "c1"); custom1 = (sOpt >= 0) ? sOpt : DEFAULT_C1;
|
sOpt = extractModeDefaults(fx, "c1"); custom1 = (sOpt >= 0) ? sOpt : DEFAULT_C1;
|
||||||
@ -573,6 +592,9 @@ Segment &Segment::setMode(uint8_t fx, bool loadDefaults) {
|
|||||||
sOpt = extractModeDefaults(fx, "mY"); if (sOpt >= 0) mirror_y = (bool)sOpt; // NOTE: setting this option is a risky business
|
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); //else setPalette(0);
|
sOpt = extractModeDefaults(fx, "pal"); if (sOpt >= 0) setPalette(sOpt); //else setPalette(0);
|
||||||
}
|
}
|
||||||
|
sOpt = extractModeDefaults(fx, "pal"); // always extract 'pal' to set _default_palette
|
||||||
|
if(sOpt <= 0) sOpt = 6; // partycolors if zero or not set
|
||||||
|
_default_palette = sOpt; // _deault_palette is loaded into pal0 in loadPalette() (if selected)
|
||||||
markForReset();
|
markForReset();
|
||||||
stateChanged = true; // send UDP/WS broadcast
|
stateChanged = true; // send UDP/WS broadcast
|
||||||
}
|
}
|
||||||
@ -591,14 +613,14 @@ Segment &Segment::setPalette(uint8_t pal) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 2D matrix
|
// 2D matrix
|
||||||
unsigned IRAM_ATTR Segment::virtualWidth() const {
|
unsigned Segment::virtualWidth() const {
|
||||||
unsigned groupLen = groupLength();
|
unsigned groupLen = groupLength();
|
||||||
unsigned vWidth = ((transpose ? height() : width()) + groupLen - 1) / groupLen;
|
unsigned vWidth = ((transpose ? height() : width()) + groupLen - 1) / groupLen;
|
||||||
if (mirror) vWidth = (vWidth + 1) /2; // divide by 2 if mirror, leave at least a single LED
|
if (mirror) vWidth = (vWidth + 1) /2; // divide by 2 if mirror, leave at least a single LED
|
||||||
return vWidth;
|
return vWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned IRAM_ATTR Segment::virtualHeight() const {
|
unsigned Segment::virtualHeight() const {
|
||||||
unsigned groupLen = groupLength();
|
unsigned groupLen = groupLength();
|
||||||
unsigned vHeight = ((transpose ? width() : height()) + groupLen - 1) / groupLen;
|
unsigned vHeight = ((transpose ? width() : height()) + groupLen - 1) / groupLen;
|
||||||
if (mirror_y) vHeight = (vHeight + 1) /2; // divide by 2 if mirror, leave at least a single LED
|
if (mirror_y) vHeight = (vHeight + 1) /2; // divide by 2 if mirror, leave at least a single LED
|
||||||
@ -642,7 +664,7 @@ static int getPinwheelLength(int vW, int vH) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// 1D strip
|
// 1D strip
|
||||||
uint16_t IRAM_ATTR Segment::virtualLength() const {
|
uint16_t Segment::virtualLength() const {
|
||||||
#ifndef WLED_DISABLE_2D
|
#ifndef WLED_DISABLE_2D
|
||||||
if (is2D()) {
|
if (is2D()) {
|
||||||
unsigned vW = virtualWidth();
|
unsigned vW = virtualWidth();
|
||||||
@ -676,18 +698,31 @@ uint16_t IRAM_ATTR Segment::virtualLength() const {
|
|||||||
|
|
||||||
void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col)
|
void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col)
|
||||||
{
|
{
|
||||||
if (!isActive()) return; // not active
|
if (!isActive() || i < 0) return; // not active or invalid index
|
||||||
#ifndef WLED_DISABLE_2D
|
#ifndef WLED_DISABLE_2D
|
||||||
int vStrip = i>>16; // hack to allow running on virtual strips (2D segment columns/rows)
|
int vStrip = 0;
|
||||||
#endif
|
#endif
|
||||||
i &= 0xFFFF;
|
int vL = vLength();
|
||||||
|
// if the 1D effect is using virtual strips "i" will have virtual strip id stored in upper 16 bits
|
||||||
if (i >= virtualLength() || i<0) return; // if pixel would fall out of segment just exit
|
// in such case "i" will be > virtualLength()
|
||||||
|
if (i >= vL) {
|
||||||
|
// check if this is a virtual strip
|
||||||
|
#ifndef WLED_DISABLE_2D
|
||||||
|
vStrip = i>>16; // hack to allow running on virtual strips (2D segment columns/rows)
|
||||||
|
i &= 0xFFFF; //truncate vstrip index
|
||||||
|
if (i >= vL) return; // if pixel would still fall out of segment just exit
|
||||||
|
#else
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef WLED_DISABLE_2D
|
#ifndef WLED_DISABLE_2D
|
||||||
if (is2D()) {
|
if (is2D()) {
|
||||||
int vH = virtualHeight(); // segment height in logical pixels
|
const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive)
|
||||||
int vW = virtualWidth();
|
const int vH = vHeight(); // segment height in logical pixels (is always >= 1)
|
||||||
|
// pre-scale color for all pixels
|
||||||
|
col = color_fade(col, _segBri);
|
||||||
|
_colorScaled = true;
|
||||||
switch (map1D2D) {
|
switch (map1D2D) {
|
||||||
case M12_Pixels:
|
case M12_Pixels:
|
||||||
// use all available pixels as a long strip
|
// use all available pixels as a long strip
|
||||||
@ -695,12 +730,12 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col)
|
|||||||
break;
|
break;
|
||||||
case M12_pBar:
|
case M12_pBar:
|
||||||
// expand 1D effect vertically or have it play on virtual strips
|
// expand 1D effect vertically or have it play on virtual strips
|
||||||
if (vStrip>0) setPixelColorXY(vStrip - 1, vH - i - 1, col);
|
if (vStrip > 0) setPixelColorXY(vStrip - 1, vH - i - 1, col);
|
||||||
else for (int x = 0; x < vW; x++) setPixelColorXY(x, vH - i - 1, col);
|
else for (int x = 0; x < vW; x++) setPixelColorXY(x, vH - i - 1, col);
|
||||||
break;
|
break;
|
||||||
case M12_pArc:
|
case M12_pArc:
|
||||||
// expand in circular fashion from center
|
// expand in circular fashion from center
|
||||||
if (i==0)
|
if (i == 0)
|
||||||
setPixelColorXY(0, 0, col);
|
setPixelColorXY(0, 0, col);
|
||||||
else {
|
else {
|
||||||
float r = i;
|
float r = i;
|
||||||
@ -779,13 +814,14 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_colorScaled = false;
|
||||||
return;
|
return;
|
||||||
} else if (Segment::maxHeight!=1 && (width()==1 || height()==1)) {
|
} else if (Segment::maxHeight != 1 && (width() == 1 || height() == 1)) {
|
||||||
if (start < Segment::maxWidth*Segment::maxHeight) {
|
if (start < Segment::maxWidth*Segment::maxHeight) {
|
||||||
// we have a vertical or horizontal 1D segment (WARNING: virtual...() may be transposed)
|
// we have a vertical or horizontal 1D segment (WARNING: virtual...() may be transposed)
|
||||||
int x = 0, y = 0;
|
int x = 0, y = 0;
|
||||||
if (virtualHeight()>1) y = i;
|
if (vHeight() > 1) y = i;
|
||||||
if (virtualWidth() >1) x = i;
|
if (vWidth() > 1) x = i;
|
||||||
setPixelColorXY(x, y, col);
|
setPixelColorXY(x, y, col);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -793,10 +829,8 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
unsigned len = length();
|
unsigned len = length();
|
||||||
uint8_t _bri_t = currentBri();
|
// if color is unscaled
|
||||||
if (_bri_t < 255) {
|
if (!_colorScaled) col = color_fade(col, _segBri);
|
||||||
col = color_fade(col, _bri_t);
|
|
||||||
}
|
|
||||||
|
|
||||||
// expand pixel (taking into account start, grouping, spacing [and offset])
|
// expand pixel (taking into account start, grouping, spacing [and offset])
|
||||||
i = i * groupLength();
|
i = i * groupLength();
|
||||||
@ -819,14 +853,14 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col)
|
|||||||
indexMir += offset; // offset/phase
|
indexMir += offset; // offset/phase
|
||||||
if (indexMir >= stop) indexMir -= len; // wrap
|
if (indexMir >= stop) indexMir -= len; // wrap
|
||||||
#ifndef WLED_DISABLE_MODE_BLEND
|
#ifndef WLED_DISABLE_MODE_BLEND
|
||||||
if (_modeBlend) tmpCol = color_blend(strip.getPixelColor(indexMir), col, 0xFFFFU - progress(), true);
|
if (_modeBlend) tmpCol = color_blend16(strip.getPixelColor(indexMir), col, uint16_t(0xFFFFU - progress()));
|
||||||
#endif
|
#endif
|
||||||
strip.setPixelColor(indexMir, tmpCol);
|
strip.setPixelColor(indexMir, tmpCol);
|
||||||
}
|
}
|
||||||
indexSet += offset; // offset/phase
|
indexSet += offset; // offset/phase
|
||||||
if (indexSet >= stop) indexSet -= len; // wrap
|
if (indexSet >= stop) indexSet -= len; // wrap
|
||||||
#ifndef WLED_DISABLE_MODE_BLEND
|
#ifndef WLED_DISABLE_MODE_BLEND
|
||||||
if (_modeBlend) tmpCol = color_blend(strip.getPixelColor(indexSet), col, 0xFFFFU - progress(), true);
|
if (_modeBlend) tmpCol = color_blend16(strip.getPixelColor(indexSet), col, uint16_t(0xFFFFU - progress()));
|
||||||
#endif
|
#endif
|
||||||
strip.setPixelColor(indexSet, tmpCol);
|
strip.setPixelColor(indexSet, tmpCol);
|
||||||
}
|
}
|
||||||
@ -871,23 +905,20 @@ void Segment::setPixelColor(float i, uint32_t col, bool aa)
|
|||||||
uint32_t IRAM_ATTR_YN Segment::getPixelColor(int i) const
|
uint32_t IRAM_ATTR_YN Segment::getPixelColor(int i) const
|
||||||
{
|
{
|
||||||
if (!isActive()) return 0; // not active
|
if (!isActive()) return 0; // not active
|
||||||
#ifndef WLED_DISABLE_2D
|
|
||||||
int vStrip = i>>16;
|
|
||||||
#endif
|
|
||||||
i &= 0xFFFF;
|
|
||||||
|
|
||||||
#ifndef WLED_DISABLE_2D
|
#ifndef WLED_DISABLE_2D
|
||||||
if (is2D()) {
|
if (is2D()) {
|
||||||
int vH = virtualHeight(); // segment height in logical pixels
|
const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive)
|
||||||
int vW = virtualWidth();
|
const int vH = vHeight(); // segment height in logical pixels (is always >= 1)
|
||||||
switch (map1D2D) {
|
switch (map1D2D) {
|
||||||
case M12_Pixels:
|
case M12_Pixels:
|
||||||
return getPixelColorXY(i % vW, i / vW);
|
return getPixelColorXY(i % vW, i / vW);
|
||||||
break;
|
break;
|
||||||
case M12_pBar:
|
case M12_pBar: {
|
||||||
if (vStrip>0) return getPixelColorXY(vStrip - 1, vH - i -1);
|
int vStrip = i>>16; // virtual strips are only relevant in Bar expansion mode
|
||||||
else return getPixelColorXY(0, vH - i -1);
|
if (vStrip > 0) return getPixelColorXY(vStrip - 1, vH - (i & 0xFFFF) -1);
|
||||||
break;
|
else return getPixelColorXY(0, vH - i -1);
|
||||||
|
break; }
|
||||||
case M12_pArc:
|
case M12_pArc:
|
||||||
if (i >= vW && i >= vH) {
|
if (i >= vW && i >= vH) {
|
||||||
unsigned vI = sqrt16(i*i/2);
|
unsigned vI = sqrt16(i*i/2);
|
||||||
@ -931,7 +962,7 @@ uint32_t IRAM_ATTR_YN Segment::getPixelColor(int i) const
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (reverse) i = virtualLength() - i - 1;
|
if (reverse) i = vLength() - i - 1;
|
||||||
i *= groupLength();
|
i *= groupLength();
|
||||||
i += start;
|
i += start;
|
||||||
// offset/phase
|
// offset/phase
|
||||||
@ -940,7 +971,7 @@ uint32_t IRAM_ATTR_YN Segment::getPixelColor(int i) const
|
|||||||
return strip.getPixelColor(i);
|
return strip.getPixelColor(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t Segment::differs(Segment& b) const {
|
uint8_t Segment::differs(const Segment& b) const {
|
||||||
uint8_t d = 0;
|
uint8_t d = 0;
|
||||||
if (start != b.start) d |= SEG_DIFFERS_BOUNDS;
|
if (start != b.start) d |= SEG_DIFFERS_BOUNDS;
|
||||||
if (stop != b.stop) d |= SEG_DIFFERS_BOUNDS;
|
if (stop != b.stop) d |= SEG_DIFFERS_BOUNDS;
|
||||||
@ -1020,12 +1051,16 @@ void Segment::refreshLightCapabilities() {
|
|||||||
*/
|
*/
|
||||||
void Segment::fill(uint32_t c) {
|
void Segment::fill(uint32_t c) {
|
||||||
if (!isActive()) return; // not active
|
if (!isActive()) return; // not active
|
||||||
const int cols = is2D() ? virtualWidth() : virtualLength();
|
const int cols = is2D() ? vWidth() : vLength();
|
||||||
const int rows = virtualHeight(); // will be 1 for 1D
|
const int rows = vHeight(); // will be 1 for 1D
|
||||||
|
// pre-scale color for all pixels
|
||||||
|
c = color_fade(c, _segBri);
|
||||||
|
_colorScaled = true;
|
||||||
for (int y = 0; y < rows; y++) for (int x = 0; x < cols; x++) {
|
for (int y = 0; y < rows; y++) for (int x = 0; x < cols; x++) {
|
||||||
if (is2D()) setPixelColorXY(x, y, c);
|
if (is2D()) setPixelColorXY(x, y, c);
|
||||||
else setPixelColor(x, c);
|
else setPixelColor(x, c);
|
||||||
}
|
}
|
||||||
|
_colorScaled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1033,8 +1068,8 @@ void Segment::fill(uint32_t c) {
|
|||||||
*/
|
*/
|
||||||
void Segment::fade_out(uint8_t rate) {
|
void Segment::fade_out(uint8_t rate) {
|
||||||
if (!isActive()) return; // not active
|
if (!isActive()) return; // not active
|
||||||
const int cols = is2D() ? virtualWidth() : virtualLength();
|
const int cols = is2D() ? vWidth() : vLength();
|
||||||
const int rows = virtualHeight(); // will be 1 for 1D
|
const int rows = vHeight(); // will be 1 for 1D
|
||||||
|
|
||||||
rate = (255-rate) >> 1;
|
rate = (255-rate) >> 1;
|
||||||
float mappedRate = 1.0f / (float(rate) + 1.1f);
|
float mappedRate = 1.0f / (float(rate) + 1.1f);
|
||||||
@ -1072,8 +1107,8 @@ void Segment::fade_out(uint8_t rate) {
|
|||||||
// fades all pixels to black using nscale8()
|
// fades all pixels to black using nscale8()
|
||||||
void Segment::fadeToBlackBy(uint8_t fadeBy) {
|
void Segment::fadeToBlackBy(uint8_t fadeBy) {
|
||||||
if (!isActive() || fadeBy == 0) return; // optimization - no scaling to apply
|
if (!isActive() || fadeBy == 0) return; // optimization - no scaling to apply
|
||||||
const int cols = is2D() ? virtualWidth() : virtualLength();
|
const int cols = is2D() ? vWidth() : vLength();
|
||||||
const int rows = virtualHeight(); // will be 1 for 1D
|
const int rows = vHeight(); // will be 1 for 1D
|
||||||
|
|
||||||
for (int y = 0; y < rows; y++) for (int x = 0; x < cols; x++) {
|
for (int y = 0; y < rows; y++) for (int x = 0; x < cols; x++) {
|
||||||
if (is2D()) setPixelColorXY(x, y, color_fade(getPixelColorXY(x,y), 255-fadeBy));
|
if (is2D()) setPixelColorXY(x, y, color_fade(getPixelColorXY(x,y), 255-fadeBy));
|
||||||
@ -1083,20 +1118,21 @@ void Segment::fadeToBlackBy(uint8_t fadeBy) {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* blurs segment content, source: FastLED colorutils.cpp
|
* blurs segment content, source: FastLED colorutils.cpp
|
||||||
|
* Note: for blur_amount > 215 this function does not work properly (creates alternating pattern)
|
||||||
*/
|
*/
|
||||||
void Segment::blur(uint8_t blur_amount, bool smear) {
|
void Segment::blur(uint8_t blur_amount, bool smear) {
|
||||||
if (!isActive() || blur_amount == 0) return; // optimization: 0 means "don't blur"
|
if (!isActive() || blur_amount == 0) return; // optimization: 0 means "don't blur"
|
||||||
#ifndef WLED_DISABLE_2D
|
#ifndef WLED_DISABLE_2D
|
||||||
if (is2D()) {
|
if (is2D()) {
|
||||||
// compatibility with 2D
|
// compatibility with 2D
|
||||||
blur2D(blur_amount, smear);
|
blur2D(blur_amount, blur_amount, smear); // symmetrical 2D blur
|
||||||
//box_blur(map(blur_amount,1,255,1,3), smear);
|
//box_blur(map(blur_amount,1,255,1,3), smear);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
uint8_t keep = smear ? 255 : 255 - blur_amount;
|
uint8_t keep = smear ? 255 : 255 - blur_amount;
|
||||||
uint8_t seep = blur_amount >> (1 + smear);
|
uint8_t seep = blur_amount >> 1;
|
||||||
unsigned vlength = virtualLength();
|
unsigned vlength = vLength();
|
||||||
uint32_t carryover = BLACK;
|
uint32_t carryover = BLACK;
|
||||||
uint32_t lastnew;
|
uint32_t lastnew;
|
||||||
uint32_t last;
|
uint32_t last;
|
||||||
@ -1106,12 +1142,11 @@ void Segment::blur(uint8_t blur_amount, bool smear) {
|
|||||||
uint32_t part = color_fade(cur, seep);
|
uint32_t part = color_fade(cur, seep);
|
||||||
curnew = color_fade(cur, keep);
|
curnew = color_fade(cur, keep);
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
if (carryover) curnew = color_add(curnew, carryover, true);
|
if (carryover) curnew = color_add(curnew, carryover);
|
||||||
uint32_t prev = color_add(lastnew, part, true);
|
uint32_t prev = color_add(lastnew, part);
|
||||||
// optimization: only set pixel if color has changed
|
// optimization: only set pixel if color has changed
|
||||||
if (last != prev) setPixelColor(i - 1, prev);
|
if (last != prev) setPixelColor(i - 1, prev);
|
||||||
} else // first pixel
|
} else setPixelColor(i, curnew); // first pixel
|
||||||
setPixelColor(i, curnew);
|
|
||||||
lastnew = curnew;
|
lastnew = curnew;
|
||||||
last = cur; // save original value for comparison on next iteration
|
last = cur; // save original value for comparison on next iteration
|
||||||
carryover = part;
|
carryover = part;
|
||||||
@ -1126,11 +1161,11 @@ void Segment::blur(uint8_t blur_amount, bool smear) {
|
|||||||
*/
|
*/
|
||||||
uint32_t Segment::color_wheel(uint8_t pos) const {
|
uint32_t Segment::color_wheel(uint8_t pos) const {
|
||||||
if (palette) return color_from_palette(pos, false, true, 0); // perhaps "strip.paletteBlend < 2" should be better instead of "true"
|
if (palette) return color_from_palette(pos, false, true, 0); // perhaps "strip.paletteBlend < 2" should be better instead of "true"
|
||||||
uint8_t w = W(currentColor(0));
|
uint8_t w = W(getCurrentColor(0));
|
||||||
pos = 255 - pos;
|
pos = 255 - pos;
|
||||||
if (pos < 85) {
|
if (pos < 85) {
|
||||||
return RGBW32((255 - pos * 3), 0, (pos * 3), w);
|
return RGBW32((255 - pos * 3), 0, (pos * 3), w);
|
||||||
} else if(pos < 170) {
|
} else if (pos < 170) {
|
||||||
pos -= 85;
|
pos -= 85;
|
||||||
return RGBW32(0, (pos * 3), (255 - pos * 3), w);
|
return RGBW32(0, (pos * 3), (255 - pos * 3), w);
|
||||||
} else {
|
} else {
|
||||||
@ -1149,18 +1184,21 @@ uint32_t Segment::color_wheel(uint8_t pos) const {
|
|||||||
* @returns Single color from palette
|
* @returns Single color from palette
|
||||||
*/
|
*/
|
||||||
uint32_t Segment::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri) const {
|
uint32_t Segment::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri) const {
|
||||||
uint32_t color = gamma32(currentColor(mcol));
|
uint32_t color = getCurrentColor(mcol < NUM_COLORS ? mcol : 0);
|
||||||
|
|
||||||
// default palette or no RGB support on segment
|
// default palette or no RGB support on segment
|
||||||
if ((palette == 0 && mcol < NUM_COLORS) || !_isRGB) return (pbri == 255) ? color : color_fade(color, pbri, true);
|
if ((palette == 0 && mcol < NUM_COLORS) || !_isRGB) {
|
||||||
|
return color_fade(color, pbri, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
const int vL = vLength();
|
||||||
unsigned paletteIndex = i;
|
unsigned paletteIndex = i;
|
||||||
if (mapping && virtualLength() > 1) paletteIndex = (i*255)/(virtualLength() -1);
|
if (mapping && vL > 1) paletteIndex = (i*255)/(vL -1);
|
||||||
// paletteBlend: 0 - wrap when moving, 1 - always wrap, 2 - never wrap, 3 - none (undefined)
|
// paletteBlend: 0 - wrap when moving, 1 - always wrap, 2 - never wrap, 3 - none (undefined)
|
||||||
if (!wrap && strip.paletteBlend != 3) paletteIndex = scale8(paletteIndex, 240); //cut off blend at palette "end"
|
if (!wrap && strip.paletteBlend != 3) paletteIndex = scale8(paletteIndex, 240); //cut off blend at palette "end"
|
||||||
CRGB fastled_col = ColorFromPalette(_currentPalette, paletteIndex, pbri, (strip.paletteBlend == 3)? NOBLEND:LINEARBLEND); // NOTE: paletteBlend should be global
|
CRGBW palcol = ColorFromPalette(_currentPalette, paletteIndex, pbri, (strip.paletteBlend == 3)? NOBLEND:LINEARBLEND); // NOTE: paletteBlend should be global
|
||||||
|
palcol.w = W(color);
|
||||||
|
|
||||||
return RGBW32(fastled_col.r, fastled_col.g, fastled_col.b, W(color));
|
return palcol.color32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1324,11 +1362,6 @@ void WS2812FX::service() {
|
|||||||
|
|
||||||
if (!seg.freeze) { //only run effect function if not frozen
|
if (!seg.freeze) { //only run effect function if not frozen
|
||||||
int oldCCT = BusManager::getSegmentCCT(); // store original CCT value (actually it is not Segment based)
|
int oldCCT = BusManager::getSegmentCCT(); // store original CCT value (actually it is not Segment based)
|
||||||
_virtualSegmentLength = seg.virtualLength(); //SEGLEN
|
|
||||||
_colors_t[0] = gamma32(seg.currentColor(0));
|
|
||||||
_colors_t[1] = gamma32(seg.currentColor(1));
|
|
||||||
_colors_t[2] = gamma32(seg.currentColor(2));
|
|
||||||
seg.setCurrentPalette(); // load actual palette
|
|
||||||
// when correctWB is true we need to correct/adjust RGB value according to desired CCT value, but it will also affect actual WW/CW ratio
|
// when correctWB is true we need to correct/adjust RGB value according to desired CCT value, but it will also affect actual WW/CW ratio
|
||||||
// when cctFromRgb is true we implicitly calculate WW and CW from RGB values
|
// when cctFromRgb is true we implicitly calculate WW and CW from RGB values
|
||||||
if (cctFromRgb) BusManager::setSegmentCCT(-1);
|
if (cctFromRgb) BusManager::setSegmentCCT(-1);
|
||||||
@ -1340,13 +1373,14 @@ void WS2812FX::service() {
|
|||||||
// overwritten by later effect. To enable seamless blending for every effect, additional LED buffer
|
// overwritten by later effect. To enable seamless blending for every effect, additional LED buffer
|
||||||
// would need to be allocated for each effect and then blended together for each pixel.
|
// would need to be allocated for each effect and then blended together for each pixel.
|
||||||
[[maybe_unused]] uint8_t tmpMode = seg.currentMode(); // this will return old mode while in transition
|
[[maybe_unused]] uint8_t tmpMode = seg.currentMode(); // this will return old mode while in transition
|
||||||
frameDelay = (*_mode[seg.mode])(); // run new/current mode
|
seg.beginDraw(); // set up parameters for get/setPixelColor()
|
||||||
|
frameDelay = (*_mode[seg.mode])(); // run new/current mode
|
||||||
#ifndef WLED_DISABLE_MODE_BLEND
|
#ifndef WLED_DISABLE_MODE_BLEND
|
||||||
if (modeBlending && seg.mode != tmpMode) {
|
if (modeBlending && seg.mode != tmpMode) {
|
||||||
Segment::tmpsegd_t _tmpSegData;
|
Segment::tmpsegd_t _tmpSegData;
|
||||||
Segment::modeBlend(true); // set semaphore
|
Segment::modeBlend(true); // set semaphore
|
||||||
seg.swapSegenv(_tmpSegData); // temporarily store new mode state (and swap it with transitional state)
|
seg.swapSegenv(_tmpSegData); // temporarily store new mode state (and swap it with transitional state)
|
||||||
_virtualSegmentLength = seg.virtualLength(); // update SEGLEN (mapping may have changed)
|
seg.beginDraw(); // set up parameters for get/setPixelColor()
|
||||||
unsigned d2 = (*_mode[tmpMode])(); // run old mode
|
unsigned d2 = (*_mode[tmpMode])(); // run old mode
|
||||||
seg.restoreSegenv(_tmpSegData); // restore mode state (will also update transitional state)
|
seg.restoreSegenv(_tmpSegData); // restore mode state (will also update transitional state)
|
||||||
frameDelay = min(frameDelay,d2); // use shortest delay
|
frameDelay = min(frameDelay,d2); // use shortest delay
|
||||||
@ -1362,7 +1396,6 @@ void WS2812FX::service() {
|
|||||||
}
|
}
|
||||||
_segment_index++;
|
_segment_index++;
|
||||||
}
|
}
|
||||||
_virtualSegmentLength = 0;
|
|
||||||
_isServicing = false;
|
_isServicing = false;
|
||||||
_triggered = false;
|
_triggered = false;
|
||||||
|
|
||||||
@ -1412,50 +1445,12 @@ void WS2812FX::show() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
void WS2812FX::setTargetFps(unsigned fps) {
|
||||||
* Returns a true value if any of the strips are still being updated.
|
|
||||||
* On some hardware (ESP32), strip updates are done asynchronously.
|
|
||||||
*/
|
|
||||||
bool WS2812FX::isUpdating() const {
|
|
||||||
return !BusManager::canAllShow();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the refresh rate of the LED strip. Useful for finding out whether a given setup is fast enough.
|
|
||||||
* Only updates on show() or is set to 0 fps if last show is more than 2 secs ago, so accuracy varies
|
|
||||||
*/
|
|
||||||
uint16_t WS2812FX::getFps() const {
|
|
||||||
if (millis() - _lastShow > 2000) return 0;
|
|
||||||
return (FPS_MULTIPLIER * _cumulativeFps) >> FPS_CALC_SHIFT; // _cumulativeFps is stored in fixed point
|
|
||||||
}
|
|
||||||
|
|
||||||
void WS2812FX::setTargetFps(uint8_t fps) {
|
|
||||||
if (fps <= 250) _targetFps = fps;
|
if (fps <= 250) _targetFps = fps;
|
||||||
if (_targetFps > 0) _frametime = 1000 / _targetFps;
|
if (_targetFps > 0) _frametime = 1000 / _targetFps;
|
||||||
else _frametime = MIN_FRAME_DELAY; // unlimited mode
|
else _frametime = MIN_FRAME_DELAY; // unlimited mode
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
|
||||||
_segments[segid].setMode(m); // do not load defaults
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//applies to all active and selected segments
|
|
||||||
void WS2812FX::setColor(uint8_t slot, uint32_t c) {
|
|
||||||
if (slot >= NUM_COLORS) return;
|
|
||||||
|
|
||||||
for (segment &seg : _segments) {
|
|
||||||
if (seg.isActive() && seg.isSelected()) {
|
|
||||||
seg.setColor(slot, c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WS2812FX::setCCT(uint16_t k) {
|
void WS2812FX::setCCT(uint16_t k) {
|
||||||
for (segment &seg : _segments) {
|
for (segment &seg : _segments) {
|
||||||
if (seg.isActive() && seg.isSelected()) {
|
if (seg.isActive() && seg.isSelected()) {
|
||||||
@ -1502,7 +1497,7 @@ uint8_t WS2812FX::getFirstSelectedSegId() const {
|
|||||||
return getMainSegmentId();
|
return getMainSegmentId();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WS2812FX::setMainSegmentId(uint8_t n) {
|
void WS2812FX::setMainSegmentId(unsigned n) {
|
||||||
_mainSegment = 0;
|
_mainSegment = 0;
|
||||||
if (n < _segments.size()) {
|
if (n < _segments.size()) {
|
||||||
_mainSegment = n;
|
_mainSegment = n;
|
||||||
@ -1578,23 +1573,10 @@ void WS2812FX::purgeSegments() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Segment& WS2812FX::getSegment(uint8_t id) {
|
Segment& WS2812FX::getSegment(unsigned id) {
|
||||||
return _segments[id >= _segments.size() ? getMainSegmentId() : id]; // vectors
|
return _segments[id >= _segments.size() ? getMainSegmentId() : id]; // vectors
|
||||||
}
|
}
|
||||||
|
|
||||||
// sets new segment bounds, queues if that segment is currently running
|
|
||||||
void WS2812FX::setSegment(uint8_t segId, uint16_t i1, uint16_t i2, uint8_t grouping, uint8_t spacing, uint16_t offset, uint16_t startY, uint16_t stopY) {
|
|
||||||
if (segId >= getSegmentsNum()) {
|
|
||||||
if (i2 <= i1) return; // do not append empty/inactive segments
|
|
||||||
appendSegment(Segment(0, strip.getLengthTotal()));
|
|
||||||
segId = getSegmentsNum()-1; // segments are added at the end of list
|
|
||||||
}
|
|
||||||
suspend();
|
|
||||||
_segments[segId].setUp(i1, i2, grouping, spacing, offset, startY, stopY);
|
|
||||||
resume();
|
|
||||||
if (segId > 0 && segId == getSegmentsNum()-1 && i2 <= i1) _segments.pop_back(); // if last segment was deleted remove it from vector
|
|
||||||
}
|
|
||||||
|
|
||||||
void WS2812FX::resetSegments() {
|
void WS2812FX::resetSegments() {
|
||||||
_segments.clear(); // destructs all Segment as part of clearing
|
_segments.clear(); // destructs all Segment as part of clearing
|
||||||
#ifndef WLED_DISABLE_2D
|
#ifndef WLED_DISABLE_2D
|
||||||
@ -1793,7 +1775,7 @@ void WS2812FX::loadCustomPalettes() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//load custom mapping table from JSON file (called from finalizeInit() or deserializeState())
|
//load custom mapping table from JSON file (called from finalizeInit() or deserializeState())
|
||||||
bool WS2812FX::deserializeMap(uint8_t n) {
|
bool WS2812FX::deserializeMap(unsigned n) {
|
||||||
// 2D support creates its own ledmap (on the fly) if a ledmap.json exists it will overwrite built one.
|
// 2D support creates its own ledmap (on the fly) if a ledmap.json exists it will overwrite built one.
|
||||||
|
|
||||||
char fileName[32];
|
char fileName[32];
|
||||||
@ -1845,14 +1827,6 @@ bool WS2812FX::deserializeMap(uint8_t n) {
|
|||||||
return (customMappingSize > 0);
|
return (customMappingSize > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t IRAM_ATTR WS2812FX::getMappedPixelIndex(uint16_t index) const {
|
|
||||||
// convert logical address to physical
|
|
||||||
if (index < customMappingSize
|
|
||||||
&& (realtimeMode == REALTIME_MODE_INACTIVE || realtimeRespectLedMaps)) index = customMappingTable[index];
|
|
||||||
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
WS2812FX* WS2812FX::instance = nullptr;
|
WS2812FX* WS2812FX::instance = nullptr;
|
||||||
|
|
||||||
@ -1865,5 +1839,5 @@ const char JSON_palette_names[] PROGMEM = R"=====([
|
|||||||
"Magenta","Magred","Yelmag","Yelblu","Orange & Teal","Tiamat","April Night","Orangery","C9","Sakura",
|
"Magenta","Magred","Yelmag","Yelblu","Orange & Teal","Tiamat","April Night","Orangery","C9","Sakura",
|
||||||
"Aurora","Atlantica","C9 2","C9 New","Temperature","Aurora 2","Retro Clown","Candy","Toxy Reaf","Fairy Reaf",
|
"Aurora","Atlantica","C9 2","C9 New","Temperature","Aurora 2","Retro Clown","Candy","Toxy Reaf","Fairy Reaf",
|
||||||
"Semi Blue","Pink Candy","Red Reaf","Aqua Flash","Yelblu Hot","Lite Light","Red Flash","Blink Red","Red Shift","Red Tide",
|
"Semi Blue","Pink Candy","Red Reaf","Aqua Flash","Yelblu Hot","Lite Light","Red Flash","Blink Red","Red Shift","Red Tide",
|
||||||
"Candy2"
|
"Candy2","Traffic Light"
|
||||||
])=====";
|
])=====";
|
||||||
|
@ -126,10 +126,10 @@ void onAlexaChange(EspalexaDevice* dev)
|
|||||||
} else {
|
} else {
|
||||||
colorKtoRGB(k, rgbw);
|
colorKtoRGB(k, rgbw);
|
||||||
}
|
}
|
||||||
strip.setColor(0, RGBW32(rgbw[0], rgbw[1], rgbw[2], rgbw[3]));
|
strip.getMainSegment().setColor(0, RGBW32(rgbw[0], rgbw[1], rgbw[2], rgbw[3]));
|
||||||
} else {
|
} else {
|
||||||
uint32_t color = dev->getRGB();
|
uint32_t color = dev->getRGB();
|
||||||
strip.setColor(0, color);
|
strip.getMainSegment().setColor(0, color);
|
||||||
}
|
}
|
||||||
stateUpdated(CALL_MODE_ALEXA);
|
stateUpdated(CALL_MODE_ALEXA);
|
||||||
}
|
}
|
||||||
|
@ -155,16 +155,6 @@ BusDigital::BusDigital(BusConfig &bc, uint8_t nr, const ColorOrderMap &com)
|
|||||||
DEBUG_PRINTF_P(PSTR("%successfully inited strip %u (len %u) with type %u and pins %u,%u (itype %u). mA=%d/%d\n"), _valid?"S":"Uns", nr, bc.count, bc.type, _pins[0], is2Pin(bc.type)?_pins[1]:255, _iType, _milliAmpsPerLed, _milliAmpsMax);
|
DEBUG_PRINTF_P(PSTR("%successfully inited strip %u (len %u) with type %u and pins %u,%u (itype %u). mA=%d/%d\n"), _valid?"S":"Uns", nr, bc.count, bc.type, _pins[0], is2Pin(bc.type)?_pins[1]:255, _iType, _milliAmpsPerLed, _milliAmpsMax);
|
||||||
}
|
}
|
||||||
|
|
||||||
//fine tune power estimation constants for your setup
|
|
||||||
//you can set it to 0 if the ESP is powered by USB and the LEDs by external
|
|
||||||
#ifndef MA_FOR_ESP
|
|
||||||
#ifdef ESP8266
|
|
||||||
#define MA_FOR_ESP 80 //how much mA does the ESP use (Wemos D1 about 80mA)
|
|
||||||
#else
|
|
||||||
#define MA_FOR_ESP 120 //how much mA does the ESP use (ESP32 about 120mA)
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//DISCLAIMER
|
//DISCLAIMER
|
||||||
//The following function attemps to calculate the current LED power usage,
|
//The following function attemps to calculate the current LED power usage,
|
||||||
//and will limit the brightness to stay below a set amperage threshold.
|
//and will limit the brightness to stay below a set amperage threshold.
|
||||||
@ -306,22 +296,22 @@ void BusDigital::setStatusPixel(uint32_t c) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IRAM_ATTR BusDigital::setPixelColor(uint16_t pix, uint32_t c) {
|
void IRAM_ATTR BusDigital::setPixelColor(unsigned pix, uint32_t c) {
|
||||||
if (!_valid) return;
|
if (!_valid) return;
|
||||||
uint8_t cctWW = 0, cctCW = 0;
|
|
||||||
if (hasWhite()) c = autoWhiteCalc(c);
|
if (hasWhite()) c = autoWhiteCalc(c);
|
||||||
if (Bus::_cct >= 1900) c = colorBalanceFromKelvin(Bus::_cct, c); //color correction from CCT
|
if (Bus::_cct >= 1900) c = colorBalanceFromKelvin(Bus::_cct, c); //color correction from CCT
|
||||||
if (_data) {
|
if (_data) {
|
||||||
size_t offset = pix * getNumberOfChannels();
|
size_t offset = pix * getNumberOfChannels();
|
||||||
|
uint8_t* dataptr = _data + offset;
|
||||||
if (hasRGB()) {
|
if (hasRGB()) {
|
||||||
_data[offset++] = R(c);
|
*dataptr++ = R(c);
|
||||||
_data[offset++] = G(c);
|
*dataptr++ = G(c);
|
||||||
_data[offset++] = B(c);
|
*dataptr++ = B(c);
|
||||||
}
|
}
|
||||||
if (hasWhite()) _data[offset++] = W(c);
|
if (hasWhite()) *dataptr++ = W(c);
|
||||||
// unfortunately as a segment may span multiple buses or a bus may contain multiple segments and each segment may have different CCT
|
// unfortunately as a segment may span multiple buses or a bus may contain multiple segments and each segment may have different CCT
|
||||||
// we need to store CCT value for each pixel (if there is a color correction in play, convert K in CCT ratio)
|
// we need to store CCT value for each pixel (if there is a color correction in play, convert K in CCT ratio)
|
||||||
if (hasCCT()) _data[offset] = Bus::_cct >= 1900 ? (Bus::_cct - 1900) >> 5 : (Bus::_cct < 0 ? 127 : Bus::_cct); // TODO: if _cct == -1 we simply ignore it
|
if (hasCCT()) *dataptr = Bus::_cct >= 1900 ? (Bus::_cct - 1900) >> 5 : (Bus::_cct < 0 ? 127 : Bus::_cct); // TODO: if _cct == -1 we simply ignore it
|
||||||
} else {
|
} else {
|
||||||
if (_reversed) pix = _len - pix -1;
|
if (_reversed) pix = _len - pix -1;
|
||||||
pix += _skip;
|
pix += _skip;
|
||||||
@ -336,16 +326,22 @@ void IRAM_ATTR BusDigital::setPixelColor(uint16_t pix, uint32_t c) {
|
|||||||
case 2: c = RGBW32(R(cOld), G(cOld), W(c) , 0); break;
|
case 2: c = RGBW32(R(cOld), G(cOld), W(c) , 0); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (hasCCT()) Bus::calculateCCT(c, cctWW, cctCW);
|
uint16_t wwcw = 0;
|
||||||
PolyBus::setPixelColor(_busPtr, _iType, pix, c, co, (cctCW<<8) | cctWW);
|
if (hasCCT()) {
|
||||||
|
uint8_t cctWW = 0, cctCW = 0;
|
||||||
|
Bus::calculateCCT(c, cctWW, cctCW);
|
||||||
|
wwcw = (cctCW<<8) | cctWW;
|
||||||
|
}
|
||||||
|
|
||||||
|
PolyBus::setPixelColor(_busPtr, _iType, pix, c, co, wwcw);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns original color if global buffering is enabled, else returns lossly restored color from bus
|
// returns original color if global buffering is enabled, else returns lossly restored color from bus
|
||||||
uint32_t IRAM_ATTR BusDigital::getPixelColor(uint16_t pix) const {
|
uint32_t IRAM_ATTR BusDigital::getPixelColor(unsigned pix) const {
|
||||||
if (!_valid) return 0;
|
if (!_valid) return 0;
|
||||||
if (_data) {
|
if (_data) {
|
||||||
size_t offset = pix * getNumberOfChannels();
|
const size_t offset = pix * getNumberOfChannels();
|
||||||
uint32_t c;
|
uint32_t c;
|
||||||
if (!hasRGB()) {
|
if (!hasRGB()) {
|
||||||
c = RGBW32(_data[offset], _data[offset], _data[offset], _data[offset]);
|
c = RGBW32(_data[offset], _data[offset], _data[offset], _data[offset]);
|
||||||
@ -356,7 +352,7 @@ uint32_t IRAM_ATTR BusDigital::getPixelColor(uint16_t pix) const {
|
|||||||
} else {
|
} else {
|
||||||
if (_reversed) pix = _len - pix -1;
|
if (_reversed) pix = _len - pix -1;
|
||||||
pix += _skip;
|
pix += _skip;
|
||||||
unsigned co = _colorOrderMap.getPixelColorOrder(pix+_start, _colorOrder);
|
const unsigned co = _colorOrderMap.getPixelColorOrder(pix+_start, _colorOrder);
|
||||||
uint32_t c = restoreColorLossy(PolyBus::getPixelColor(_busPtr, _iType, (_type==TYPE_WS2812_1CH_X3) ? IC_INDEX_WS2812_1CH_3X(pix) : pix, co),_bri);
|
uint32_t c = restoreColorLossy(PolyBus::getPixelColor(_busPtr, _iType, (_type==TYPE_WS2812_1CH_X3) ? IC_INDEX_WS2812_1CH_3X(pix) : pix, co),_bri);
|
||||||
if (_type == TYPE_WS2812_1CH_X3) { // map to correct IC, each controls 3 LEDs
|
if (_type == TYPE_WS2812_1CH_X3) { // map to correct IC, each controls 3 LEDs
|
||||||
unsigned r = R(c);
|
unsigned r = R(c);
|
||||||
@ -501,7 +497,7 @@ BusPwm::BusPwm(BusConfig &bc)
|
|||||||
DEBUG_PRINTF_P(PSTR("%successfully inited PWM strip with type %u, frequency %u, bit depth %u and pins %u,%u,%u,%u,%u\n"), _valid?"S":"Uns", bc.type, _frequency, _depth, _pins[0], _pins[1], _pins[2], _pins[3], _pins[4]);
|
DEBUG_PRINTF_P(PSTR("%successfully inited PWM strip with type %u, frequency %u, bit depth %u and pins %u,%u,%u,%u,%u\n"), _valid?"S":"Uns", bc.type, _frequency, _depth, _pins[0], _pins[1], _pins[2], _pins[3], _pins[4]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BusPwm::setPixelColor(uint16_t pix, uint32_t c) {
|
void BusPwm::setPixelColor(unsigned pix, uint32_t c) {
|
||||||
if (pix != 0 || !_valid) return; //only react to first pixel
|
if (pix != 0 || !_valid) return; //only react to first pixel
|
||||||
if (_type != TYPE_ANALOG_3CH) c = autoWhiteCalc(c);
|
if (_type != TYPE_ANALOG_3CH) c = autoWhiteCalc(c);
|
||||||
if (Bus::_cct >= 1900 && (_type == TYPE_ANALOG_3CH || _type == TYPE_ANALOG_4CH)) {
|
if (Bus::_cct >= 1900 && (_type == TYPE_ANALOG_3CH || _type == TYPE_ANALOG_4CH)) {
|
||||||
@ -538,7 +534,7 @@ void BusPwm::setPixelColor(uint16_t pix, uint32_t c) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//does no index check
|
//does no index check
|
||||||
uint32_t BusPwm::getPixelColor(uint16_t pix) const {
|
uint32_t BusPwm::getPixelColor(unsigned pix) const {
|
||||||
if (!_valid) return 0;
|
if (!_valid) return 0;
|
||||||
// TODO getting the reverse from CCT is involved (a quick approximation when CCT blending is ste to 0 implemented)
|
// TODO getting the reverse from CCT is involved (a quick approximation when CCT blending is ste to 0 implemented)
|
||||||
switch (_type) {
|
switch (_type) {
|
||||||
@ -567,19 +563,15 @@ void BusPwm::show() {
|
|||||||
const unsigned maxBri = (1<<_depth); // possible values: 16384 (14), 8192 (13), 4096 (12), 2048 (11), 1024 (10), 512 (9) and 256 (8)
|
const unsigned maxBri = (1<<_depth); // possible values: 16384 (14), 8192 (13), 4096 (12), 2048 (11), 1024 (10), 512 (9) and 256 (8)
|
||||||
[[maybe_unused]] const unsigned bitShift = dithering * 4; // if dithering, _depth is 12 bit but LEDC channel is set to 8 bit (using 4 fractional bits)
|
[[maybe_unused]] const unsigned bitShift = dithering * 4; // if dithering, _depth is 12 bit but LEDC channel is set to 8 bit (using 4 fractional bits)
|
||||||
|
|
||||||
// use CIE brightness formula (cubic) to fit (or approximate linearity of) human eye perceived brightness
|
// use CIE brightness formula (linear + cubic) to approximate human eye perceived brightness
|
||||||
// the formula is based on 12 bit resolution as there is no need for greater precision
|
|
||||||
// see: https://en.wikipedia.org/wiki/Lightness
|
// see: https://en.wikipedia.org/wiki/Lightness
|
||||||
unsigned pwmBri = (unsigned)_bri * 100; // enlarge to use integer math for linear response
|
unsigned pwmBri = _bri;
|
||||||
if (pwmBri < 2040) {
|
if (pwmBri < 21) { // linear response for values [0-20]
|
||||||
// linear response for values [0-20]
|
pwmBri = (pwmBri * maxBri + 2300 / 2) / 2300 ; // adding '0.5' before division for correct rounding, 2300 gives a good match to CIE curve
|
||||||
pwmBri = ((pwmBri << 12) + 115043) / 230087; //adding '0.5' before division for correct rounding
|
} else { // cubic response for values [21-255]
|
||||||
} else {
|
float temp = float(pwmBri + 41) / float(255 + 41); // 41 is to match offset & slope to linear part
|
||||||
// cubic response for values [21-255]
|
temp = temp * temp * temp * (float)maxBri;
|
||||||
pwmBri += 4080;
|
pwmBri = (unsigned)temp; // pwmBri is in range [0-maxBri] C
|
||||||
float temp = (float)pwmBri / 29580.0f;
|
|
||||||
temp = temp * temp * temp * (float)maxBri;
|
|
||||||
pwmBri = (unsigned)temp; // pwmBri is in range [0-maxBri]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[[maybe_unused]] unsigned hPoint = 0; // phase shift (0 - maxBri)
|
[[maybe_unused]] unsigned hPoint = 0; // phase shift (0 - maxBri)
|
||||||
@ -674,7 +666,7 @@ BusOnOff::BusOnOff(BusConfig &bc)
|
|||||||
DEBUG_PRINTF_P(PSTR("%successfully inited On/Off strip with pin %u\n"), _valid?"S":"Uns", _pin);
|
DEBUG_PRINTF_P(PSTR("%successfully inited On/Off strip with pin %u\n"), _valid?"S":"Uns", _pin);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BusOnOff::setPixelColor(uint16_t pix, uint32_t c) {
|
void BusOnOff::setPixelColor(unsigned pix, uint32_t c) {
|
||||||
if (pix != 0 || !_valid) return; //only react to first pixel
|
if (pix != 0 || !_valid) return; //only react to first pixel
|
||||||
c = autoWhiteCalc(c);
|
c = autoWhiteCalc(c);
|
||||||
uint8_t r = R(c);
|
uint8_t r = R(c);
|
||||||
@ -684,7 +676,7 @@ void BusOnOff::setPixelColor(uint16_t pix, uint32_t c) {
|
|||||||
_data[0] = bool(r|g|b|w) && bool(_bri) ? 0xFF : 0;
|
_data[0] = bool(r|g|b|w) && bool(_bri) ? 0xFF : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t BusOnOff::getPixelColor(uint16_t pix) const {
|
uint32_t BusOnOff::getPixelColor(unsigned pix) const {
|
||||||
if (!_valid) return 0;
|
if (!_valid) return 0;
|
||||||
return RGBW32(_data[0], _data[0], _data[0], _data[0]);
|
return RGBW32(_data[0], _data[0], _data[0], _data[0]);
|
||||||
}
|
}
|
||||||
@ -734,7 +726,7 @@ BusNetwork::BusNetwork(BusConfig &bc)
|
|||||||
DEBUG_PRINTF_P(PSTR("%successfully inited virtual strip with type %u and IP %u.%u.%u.%u\n"), _valid?"S":"Uns", bc.type, bc.pins[0], bc.pins[1], bc.pins[2], bc.pins[3]);
|
DEBUG_PRINTF_P(PSTR("%successfully inited virtual strip with type %u and IP %u.%u.%u.%u\n"), _valid?"S":"Uns", bc.type, bc.pins[0], bc.pins[1], bc.pins[2], bc.pins[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BusNetwork::setPixelColor(uint16_t pix, uint32_t c) {
|
void BusNetwork::setPixelColor(unsigned pix, uint32_t c) {
|
||||||
if (!_valid || pix >= _len) return;
|
if (!_valid || pix >= _len) return;
|
||||||
if (_hasWhite) c = autoWhiteCalc(c);
|
if (_hasWhite) c = autoWhiteCalc(c);
|
||||||
if (Bus::_cct >= 1900) c = colorBalanceFromKelvin(Bus::_cct, c); //color correction from CCT
|
if (Bus::_cct >= 1900) c = colorBalanceFromKelvin(Bus::_cct, c); //color correction from CCT
|
||||||
@ -745,7 +737,7 @@ void BusNetwork::setPixelColor(uint16_t pix, uint32_t c) {
|
|||||||
if (_hasWhite) _data[offset+3] = W(c);
|
if (_hasWhite) _data[offset+3] = W(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t BusNetwork::getPixelColor(uint16_t pix) const {
|
uint32_t BusNetwork::getPixelColor(unsigned pix) const {
|
||||||
if (!_valid || pix >= _len) return 0;
|
if (!_valid || pix >= _len) return 0;
|
||||||
unsigned offset = pix * _UDPchannels;
|
unsigned offset = pix * _UDPchannels;
|
||||||
return RGBW32(_data[offset], _data[offset+1], _data[offset+2], (hasWhite() ? _data[offset+3] : 0));
|
return RGBW32(_data[offset], _data[offset+1], _data[offset+2], (hasWhite() ? _data[offset+3] : 0));
|
||||||
@ -943,7 +935,6 @@ void BusManager::show() {
|
|||||||
busses[i]->show();
|
busses[i]->show();
|
||||||
_milliAmpsUsed += busses[i]->getUsedCurrent();
|
_milliAmpsUsed += busses[i]->getUsedCurrent();
|
||||||
}
|
}
|
||||||
if (_milliAmpsUsed) _milliAmpsUsed += MA_FOR_ESP;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BusManager::setStatusPixel(uint32_t c) {
|
void BusManager::setStatusPixel(uint32_t c) {
|
||||||
@ -952,7 +943,7 @@ void BusManager::setStatusPixel(uint32_t c) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IRAM_ATTR BusManager::setPixelColor(uint16_t pix, uint32_t c) {
|
void IRAM_ATTR BusManager::setPixelColor(unsigned pix, uint32_t c) {
|
||||||
for (unsigned i = 0; i < numBusses; i++) {
|
for (unsigned i = 0; i < numBusses; i++) {
|
||||||
unsigned bstart = busses[i]->getStart();
|
unsigned bstart = busses[i]->getStart();
|
||||||
if (pix < bstart || pix >= bstart + busses[i]->getLength()) continue;
|
if (pix < bstart || pix >= bstart + busses[i]->getLength()) continue;
|
||||||
@ -975,7 +966,7 @@ void BusManager::setSegmentCCT(int16_t cct, bool allowWBCorrection) {
|
|||||||
Bus::setCCT(cct);
|
Bus::setCCT(cct);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t BusManager::getPixelColor(uint16_t pix) {
|
uint32_t BusManager::getPixelColor(unsigned pix) {
|
||||||
for (unsigned i = 0; i < numBusses; i++) {
|
for (unsigned i = 0; i < numBusses; i++) {
|
||||||
unsigned bstart = busses[i]->getStart();
|
unsigned bstart = busses[i]->getStart();
|
||||||
if (!busses[i]->containsPixel(pix)) continue;
|
if (!busses[i]->containsPixel(pix)) continue;
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "const.h"
|
#include "const.h"
|
||||||
|
#include "pin_manager.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
//colors.cpp
|
//colors.cpp
|
||||||
@ -83,10 +84,10 @@ class Bus {
|
|||||||
virtual void show() = 0;
|
virtual void show() = 0;
|
||||||
virtual bool canShow() const { return true; }
|
virtual bool canShow() const { return true; }
|
||||||
virtual void setStatusPixel(uint32_t c) {}
|
virtual void setStatusPixel(uint32_t c) {}
|
||||||
virtual void setPixelColor(uint16_t pix, uint32_t c) = 0;
|
virtual void setPixelColor(unsigned pix, uint32_t c) = 0;
|
||||||
virtual void setBrightness(uint8_t b) { _bri = b; };
|
virtual void setBrightness(uint8_t b) { _bri = b; };
|
||||||
virtual void setColorOrder(uint8_t co) {}
|
virtual void setColorOrder(uint8_t co) {}
|
||||||
virtual uint32_t getPixelColor(uint16_t pix) const { return 0; }
|
virtual uint32_t getPixelColor(unsigned pix) const { return 0; }
|
||||||
virtual uint8_t getPins(uint8_t* pinArray = nullptr) const { return 0; }
|
virtual uint8_t getPins(uint8_t* pinArray = nullptr) const { return 0; }
|
||||||
virtual uint16_t getLength() const { return isOk() ? _len : 0; }
|
virtual uint16_t getLength() const { return isOk() ? _len : 0; }
|
||||||
virtual uint8_t getColorOrder() const { return COL_ORDER_RGB; }
|
virtual uint8_t getColorOrder() const { return COL_ORDER_RGB; }
|
||||||
@ -110,7 +111,7 @@ class Bus {
|
|||||||
inline void setStart(uint16_t start) { _start = start; }
|
inline void setStart(uint16_t start) { _start = start; }
|
||||||
inline void setAutoWhiteMode(uint8_t m) { if (m < 5) _autoWhiteMode = m; }
|
inline void setAutoWhiteMode(uint8_t m) { if (m < 5) _autoWhiteMode = m; }
|
||||||
inline uint8_t getAutoWhiteMode() const { return _autoWhiteMode; }
|
inline uint8_t getAutoWhiteMode() const { return _autoWhiteMode; }
|
||||||
inline uint8_t getNumberOfChannels() const { return hasWhite() + 3*hasRGB() + hasCCT(); }
|
inline uint32_t getNumberOfChannels() const { return hasWhite() + 3*hasRGB() + hasCCT(); }
|
||||||
inline uint16_t getStart() const { return _start; }
|
inline uint16_t getStart() const { return _start; }
|
||||||
inline uint8_t getType() const { return _type; }
|
inline uint8_t getType() const { return _type; }
|
||||||
inline bool isOk() const { return _valid; }
|
inline bool isOk() const { return _valid; }
|
||||||
@ -119,8 +120,8 @@ class Bus {
|
|||||||
inline bool containsPixel(uint16_t pix) const { return pix >= _start && pix < _start + _len; }
|
inline bool containsPixel(uint16_t pix) const { return pix >= _start && pix < _start + _len; }
|
||||||
|
|
||||||
static inline std::vector<LEDType> getLEDTypes() { return {{TYPE_NONE, "", PSTR("None")}}; } // not used. just for reference for derived classes
|
static inline std::vector<LEDType> getLEDTypes() { return {{TYPE_NONE, "", PSTR("None")}}; } // not used. just for reference for derived classes
|
||||||
static constexpr uint8_t getNumberOfPins(uint8_t type) { return isVirtual(type) ? 4 : isPWM(type) ? numPWMPins(type) : is2Pin(type) + 1; } // credit @PaoloTK
|
static constexpr uint32_t getNumberOfPins(uint8_t type) { return isVirtual(type) ? 4 : isPWM(type) ? numPWMPins(type) : is2Pin(type) + 1; } // credit @PaoloTK
|
||||||
static constexpr uint8_t getNumberOfChannels(uint8_t type) { return hasWhite(type) + 3*hasRGB(type) + hasCCT(type); }
|
static constexpr uint32_t getNumberOfChannels(uint8_t type) { return hasWhite(type) + 3*hasRGB(type) + hasCCT(type); }
|
||||||
static constexpr bool hasRGB(uint8_t type) {
|
static constexpr bool hasRGB(uint8_t type) {
|
||||||
return !((type >= TYPE_WS2812_1CH && type <= TYPE_WS2812_WWA) || type == TYPE_ANALOG_1CH || type == TYPE_ANALOG_2CH || type == TYPE_ONOFF);
|
return !((type >= TYPE_WS2812_1CH && type <= TYPE_WS2812_WWA) || type == TYPE_ANALOG_1CH || type == TYPE_ANALOG_2CH || type == TYPE_ONOFF);
|
||||||
}
|
}
|
||||||
@ -204,9 +205,9 @@ class BusDigital : public Bus {
|
|||||||
bool canShow() const override;
|
bool canShow() const override;
|
||||||
void setBrightness(uint8_t b) override;
|
void setBrightness(uint8_t b) override;
|
||||||
void setStatusPixel(uint32_t c) override;
|
void setStatusPixel(uint32_t c) override;
|
||||||
[[gnu::hot]] void setPixelColor(uint16_t pix, uint32_t c) override;
|
[[gnu::hot]] void setPixelColor(unsigned pix, uint32_t c) override;
|
||||||
void setColorOrder(uint8_t colorOrder) override;
|
void setColorOrder(uint8_t colorOrder) override;
|
||||||
[[gnu::hot]] uint32_t getPixelColor(uint16_t pix) const override;
|
[[gnu::hot]] uint32_t getPixelColor(unsigned pix) const override;
|
||||||
uint8_t getColorOrder() const override { return _colorOrder; }
|
uint8_t getColorOrder() const override { return _colorOrder; }
|
||||||
uint8_t getPins(uint8_t* pinArray = nullptr) const override;
|
uint8_t getPins(uint8_t* pinArray = nullptr) const override;
|
||||||
uint8_t skippedLeds() const override { return _skip; }
|
uint8_t skippedLeds() const override { return _skip; }
|
||||||
@ -252,8 +253,8 @@ class BusPwm : public Bus {
|
|||||||
BusPwm(BusConfig &bc);
|
BusPwm(BusConfig &bc);
|
||||||
~BusPwm() { cleanup(); }
|
~BusPwm() { cleanup(); }
|
||||||
|
|
||||||
void setPixelColor(uint16_t pix, uint32_t c) override;
|
void setPixelColor(unsigned pix, uint32_t c) override;
|
||||||
uint32_t getPixelColor(uint16_t pix) const override; //does no index check
|
uint32_t getPixelColor(unsigned pix) const override; //does no index check
|
||||||
uint8_t getPins(uint8_t* pinArray = nullptr) const override;
|
uint8_t getPins(uint8_t* pinArray = nullptr) const override;
|
||||||
uint16_t getFrequency() const override { return _frequency; }
|
uint16_t getFrequency() const override { return _frequency; }
|
||||||
void show() override;
|
void show() override;
|
||||||
@ -279,8 +280,8 @@ class BusOnOff : public Bus {
|
|||||||
BusOnOff(BusConfig &bc);
|
BusOnOff(BusConfig &bc);
|
||||||
~BusOnOff() { cleanup(); }
|
~BusOnOff() { cleanup(); }
|
||||||
|
|
||||||
void setPixelColor(uint16_t pix, uint32_t c) override;
|
void setPixelColor(unsigned pix, uint32_t c) override;
|
||||||
uint32_t getPixelColor(uint16_t pix) const override;
|
uint32_t getPixelColor(unsigned pix) const override;
|
||||||
uint8_t getPins(uint8_t* pinArray) const override;
|
uint8_t getPins(uint8_t* pinArray) const override;
|
||||||
void show() override;
|
void show() override;
|
||||||
void cleanup() { PinManager::deallocatePin(_pin, PinOwner::BusOnOff); }
|
void cleanup() { PinManager::deallocatePin(_pin, PinOwner::BusOnOff); }
|
||||||
@ -299,8 +300,8 @@ class BusNetwork : public Bus {
|
|||||||
~BusNetwork() { cleanup(); }
|
~BusNetwork() { cleanup(); }
|
||||||
|
|
||||||
bool canShow() const override { return !_broadcastLock; } // this should be a return value from UDP routine if it is still sending data out
|
bool canShow() const override { return !_broadcastLock; } // this should be a return value from UDP routine if it is still sending data out
|
||||||
void setPixelColor(uint16_t pix, uint32_t c) override;
|
void setPixelColor(unsigned pix, uint32_t c) override;
|
||||||
uint32_t getPixelColor(uint16_t pix) const override;
|
uint32_t getPixelColor(unsigned pix) const override;
|
||||||
uint8_t getPins(uint8_t* pinArray = nullptr) const override;
|
uint8_t getPins(uint8_t* pinArray = nullptr) const override;
|
||||||
void show() override;
|
void show() override;
|
||||||
void cleanup();
|
void cleanup();
|
||||||
@ -363,6 +364,16 @@ struct BusConfig {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//fine tune power estimation constants for your setup
|
||||||
|
//you can set it to 0 if the ESP is powered by USB and the LEDs by external
|
||||||
|
#ifndef MA_FOR_ESP
|
||||||
|
#ifdef ESP8266
|
||||||
|
#define MA_FOR_ESP 80 //how much mA does the ESP use (Wemos D1 about 80mA)
|
||||||
|
#else
|
||||||
|
#define MA_FOR_ESP 120 //how much mA does the ESP use (ESP32 about 120mA)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
class BusManager {
|
class BusManager {
|
||||||
public:
|
public:
|
||||||
BusManager() {};
|
BusManager() {};
|
||||||
@ -370,7 +381,7 @@ class BusManager {
|
|||||||
//utility to get the approx. memory usage of a given BusConfig
|
//utility to get the approx. memory usage of a given BusConfig
|
||||||
static uint32_t memUsage(BusConfig &bc);
|
static uint32_t memUsage(BusConfig &bc);
|
||||||
static uint32_t memUsage(unsigned channels, unsigned count, unsigned buses = 1);
|
static uint32_t memUsage(unsigned channels, unsigned count, unsigned buses = 1);
|
||||||
static uint16_t currentMilliamps() { return _milliAmpsUsed; }
|
static uint16_t currentMilliamps() { return _milliAmpsUsed + MA_FOR_ESP; }
|
||||||
static uint16_t ablMilliampsMax() { return _milliAmpsMax; }
|
static uint16_t ablMilliampsMax() { return _milliAmpsMax; }
|
||||||
|
|
||||||
static int add(BusConfig &bc);
|
static int add(BusConfig &bc);
|
||||||
@ -385,13 +396,13 @@ class BusManager {
|
|||||||
static void show();
|
static void show();
|
||||||
static bool canAllShow();
|
static bool canAllShow();
|
||||||
static void setStatusPixel(uint32_t c);
|
static void setStatusPixel(uint32_t c);
|
||||||
[[gnu::hot]] static void setPixelColor(uint16_t pix, uint32_t c);
|
[[gnu::hot]] static void setPixelColor(unsigned pix, uint32_t c);
|
||||||
static void setBrightness(uint8_t b);
|
static void setBrightness(uint8_t b);
|
||||||
// for setSegmentCCT(), cct can only be in [-1,255] range; allowWBCorrection will convert it to K
|
// for setSegmentCCT(), cct can only be in [-1,255] range; allowWBCorrection will convert it to K
|
||||||
// WARNING: setSegmentCCT() is a misleading name!!! much better would be setGlobalCCT() or just setCCT()
|
// WARNING: setSegmentCCT() is a misleading name!!! much better would be setGlobalCCT() or just setCCT()
|
||||||
static void setSegmentCCT(int16_t cct, bool allowWBCorrection = false);
|
static void setSegmentCCT(int16_t cct, bool allowWBCorrection = false);
|
||||||
static inline void setMilliampsMax(uint16_t max) { _milliAmpsMax = max;}
|
static inline void setMilliampsMax(uint16_t max) { _milliAmpsMax = max;}
|
||||||
static uint32_t getPixelColor(uint16_t pix);
|
[[gnu::hot]] static uint32_t getPixelColor(unsigned pix);
|
||||||
static inline int16_t getSegmentCCT() { return Bus::getCCT(); }
|
static inline int16_t getSegmentCCT() { return Bus::getCCT(); }
|
||||||
|
|
||||||
static Bus* getBus(uint8_t busNr);
|
static Bus* getBus(uint8_t busNr);
|
||||||
|
@ -436,13 +436,12 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
|||||||
else gammaCorrectBri = false;
|
else gammaCorrectBri = false;
|
||||||
if (light_gc_col > 1.0f) gammaCorrectCol = true;
|
if (light_gc_col > 1.0f) gammaCorrectCol = true;
|
||||||
else gammaCorrectCol = false;
|
else gammaCorrectCol = false;
|
||||||
if (gammaCorrectVal > 1.0f && gammaCorrectVal <= 3) {
|
if (gammaCorrectVal <= 1.0f || gammaCorrectVal > 3) {
|
||||||
if (gammaCorrectVal != 2.8f) NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal);
|
|
||||||
} else {
|
|
||||||
gammaCorrectVal = 1.0f; // no gamma correction
|
gammaCorrectVal = 1.0f; // no gamma correction
|
||||||
gammaCorrectBri = false;
|
gammaCorrectBri = false;
|
||||||
gammaCorrectCol = false;
|
gammaCorrectCol = false;
|
||||||
}
|
}
|
||||||
|
NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal); // fill look-up table
|
||||||
|
|
||||||
JsonObject light_tr = light["tr"];
|
JsonObject light_tr = light["tr"];
|
||||||
CJSON(fadeTransition, light_tr["mode"]);
|
CJSON(fadeTransition, light_tr["mode"]);
|
||||||
|
@ -5,61 +5,56 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* color blend function
|
* color blend function, based on FastLED blend function
|
||||||
|
* the calculation for each color is: result = (A*(amountOfA) + A + B*(amountOfB) + B) / 256 with amountOfA = 255 - amountOfB
|
||||||
*/
|
*/
|
||||||
uint32_t color_blend(uint32_t color1, uint32_t color2, uint16_t blend, bool b16) {
|
uint32_t color_blend(uint32_t color1, uint32_t color2, uint8_t blend) {
|
||||||
if (blend == 0) return color1;
|
// min / max blend checking is omitted: calls with 0 or 255 are rare, checking lowers overall performance
|
||||||
unsigned blendmax = b16 ? 0xFFFF : 0xFF;
|
uint32_t rb1 = color1 & 0x00FF00FF;
|
||||||
if (blend == blendmax) return color2;
|
uint32_t wg1 = (color1>>8) & 0x00FF00FF;
|
||||||
unsigned shift = b16 ? 16 : 8;
|
uint32_t rb2 = color2 & 0x00FF00FF;
|
||||||
|
uint32_t wg2 = (color2>>8) & 0x00FF00FF;
|
||||||
uint32_t w1 = W(color1);
|
uint32_t rb3 = ((((rb1 << 8) | rb2) + (rb2 * blend) - (rb1 * blend)) >> 8) & 0x00FF00FF;
|
||||||
uint32_t r1 = R(color1);
|
uint32_t wg3 = ((((wg1 << 8) | wg2) + (wg2 * blend) - (wg1 * blend))) & 0xFF00FF00;
|
||||||
uint32_t g1 = G(color1);
|
return rb3 | wg3;
|
||||||
uint32_t b1 = B(color1);
|
|
||||||
|
|
||||||
uint32_t w2 = W(color2);
|
|
||||||
uint32_t r2 = R(color2);
|
|
||||||
uint32_t g2 = G(color2);
|
|
||||||
uint32_t b2 = B(color2);
|
|
||||||
|
|
||||||
uint32_t w3 = ((w2 * blend) + (w1 * (blendmax - blend))) >> shift;
|
|
||||||
uint32_t r3 = ((r2 * blend) + (r1 * (blendmax - blend))) >> shift;
|
|
||||||
uint32_t g3 = ((g2 * blend) + (g1 * (blendmax - blend))) >> shift;
|
|
||||||
uint32_t b3 = ((b2 * blend) + (b1 * (blendmax - blend))) >> shift;
|
|
||||||
|
|
||||||
return RGBW32(r3, g3, b3, w3);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* color add function that preserves ratio
|
* color add function that preserves ratio
|
||||||
* idea: https://github.com/Aircoookie/WLED/pull/2465 by https://github.com/Proto-molecule
|
* original idea: https://github.com/Aircoookie/WLED/pull/2465 by https://github.com/Proto-molecule
|
||||||
|
* speed optimisations by @dedehai
|
||||||
*/
|
*/
|
||||||
uint32_t color_add(uint32_t c1, uint32_t c2, bool fast)
|
uint32_t color_add(uint32_t c1, uint32_t c2, bool preserveCR)
|
||||||
{
|
{
|
||||||
if (c1 == BLACK) return c2;
|
if (c1 == BLACK) return c2;
|
||||||
if (c2 == BLACK) return c1;
|
if (c2 == BLACK) return c1;
|
||||||
if (fast) {
|
uint32_t rb = (c1 & 0x00FF00FF) + (c2 & 0x00FF00FF); // mask and add two colors at once
|
||||||
uint8_t r = R(c1);
|
uint32_t wg = ((c1>>8) & 0x00FF00FF) + ((c2>>8) & 0x00FF00FF);
|
||||||
uint8_t g = G(c1);
|
uint32_t r = rb >> 16; // extract single color values
|
||||||
uint8_t b = B(c1);
|
uint32_t b = rb & 0xFFFF;
|
||||||
uint8_t w = W(c1);
|
uint32_t w = wg >> 16;
|
||||||
r = qadd8(r, R(c2));
|
uint32_t g = wg & 0xFFFF;
|
||||||
g = qadd8(g, G(c2));
|
|
||||||
b = qadd8(b, B(c2));
|
if (preserveCR) { // preserve color ratios
|
||||||
w = qadd8(w, W(c2));
|
uint32_t max = std::max(r,g); // check for overflow note
|
||||||
return RGBW32(r,g,b,w);
|
max = std::max(max,b);
|
||||||
|
max = std::max(max,w);
|
||||||
|
//unsigned max = r; // check for overflow note
|
||||||
|
//max = g > max ? g : max;
|
||||||
|
//max = b > max ? b : max;
|
||||||
|
//max = w > max ? w : max;
|
||||||
|
if (max > 255) {
|
||||||
|
uint32_t scale = (uint32_t(255)<<8) / max; // division of two 8bit (shifted) values does not work -> use bit shifts and multiplaction instead
|
||||||
|
rb = ((rb * scale) >> 8) & 0x00FF00FF; //
|
||||||
|
wg = (wg * scale) & 0xFF00FF00;
|
||||||
|
} else wg = wg << 8; //shift white and green back to correct position
|
||||||
|
return rb | wg;
|
||||||
} else {
|
} else {
|
||||||
uint32_t r = R(c1) + R(c2);
|
r = r > 255 ? 255 : r;
|
||||||
uint32_t g = G(c1) + G(c2);
|
g = g > 255 ? 255 : g;
|
||||||
uint32_t b = B(c1) + B(c2);
|
b = b > 255 ? 255 : b;
|
||||||
uint32_t w = W(c1) + W(c2);
|
w = w > 255 ? 255 : w;
|
||||||
unsigned max = r;
|
return RGBW32(r,g,b,w);
|
||||||
if (g > max) max = g;
|
|
||||||
if (b > max) max = b;
|
|
||||||
if (w > max) max = w;
|
|
||||||
if (max < 256) return RGBW32(r, g, b, w);
|
|
||||||
else return RGBW32(r * 255 / max, g * 255 / max, b * 255 / max, w * 255 / max);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,27 +65,53 @@ uint32_t color_add(uint32_t c1, uint32_t c2, bool fast)
|
|||||||
|
|
||||||
uint32_t color_fade(uint32_t c1, uint8_t amount, bool video)
|
uint32_t color_fade(uint32_t c1, uint8_t amount, bool video)
|
||||||
{
|
{
|
||||||
if (c1 == BLACK || amount + video == 0) return BLACK;
|
if (amount == 255) return c1;
|
||||||
|
if (c1 == BLACK || amount == 0) return BLACK;
|
||||||
uint32_t scaledcolor; // color order is: W R G B from MSB to LSB
|
uint32_t scaledcolor; // color order is: W R G B from MSB to LSB
|
||||||
uint32_t r = R(c1);
|
|
||||||
uint32_t g = G(c1);
|
|
||||||
uint32_t b = B(c1);
|
|
||||||
uint32_t w = W(c1);
|
|
||||||
uint32_t scale = amount; // 32bit for faster calculation
|
uint32_t scale = amount; // 32bit for faster calculation
|
||||||
if (video) {
|
uint32_t addRemains = 0;
|
||||||
scaledcolor = (((r * scale) >> 8) + ((r && scale) ? 1 : 0)) << 16;
|
if (!video) scale++; // add one for correct scaling using bitshifts
|
||||||
scaledcolor |= (((g * scale) >> 8) + ((g && scale) ? 1 : 0)) << 8;
|
else { // video scaling: make sure colors do not dim to zero if they started non-zero
|
||||||
scaledcolor |= ((b * scale) >> 8) + ((b && scale) ? 1 : 0);
|
addRemains = R(c1) ? 0x00010000 : 0;
|
||||||
scaledcolor |= (((w * scale) >> 8) + ((w && scale) ? 1 : 0)) << 24;
|
addRemains |= G(c1) ? 0x00000100 : 0;
|
||||||
} else {
|
addRemains |= B(c1) ? 0x00000001 : 0;
|
||||||
scaledcolor = ((r * scale) >> 8) << 16;
|
addRemains |= W(c1) ? 0x01000000 : 0;
|
||||||
scaledcolor |= ((g * scale) >> 8) << 8;
|
|
||||||
scaledcolor |= (b * scale) >> 8;
|
|
||||||
scaledcolor |= ((w * scale) >> 8) << 24;
|
|
||||||
}
|
}
|
||||||
|
uint32_t rb = (((c1 & 0x00FF00FF) * scale) >> 8) & 0x00FF00FF; // scale red and blue
|
||||||
|
uint32_t wg = (((c1 & 0xFF00FF00) >> 8) * scale) & 0xFF00FF00; // scale white and green
|
||||||
|
scaledcolor = (rb | wg) + addRemains;
|
||||||
return scaledcolor;
|
return scaledcolor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 1:1 replacement of fastled function optimized for ESP, slightly faster, more accurate and uses less flash (~ -200bytes)
|
||||||
|
uint32_t ColorFromPaletteWLED(const CRGBPalette16& pal, unsigned index, uint8_t brightness, TBlendType blendType)
|
||||||
|
{
|
||||||
|
if (blendType == LINEARBLEND_NOWRAP) {
|
||||||
|
index = (index*240) >> 8; // Blend range is affected by lo4 blend of values, remap to avoid wrapping
|
||||||
|
}
|
||||||
|
unsigned hi4 = byte(index) >> 4;
|
||||||
|
const CRGB* entry = (CRGB*)((uint8_t*)(&(pal[0])) + (hi4 * sizeof(CRGB)));
|
||||||
|
unsigned red1 = entry->r;
|
||||||
|
unsigned green1 = entry->g;
|
||||||
|
unsigned blue1 = entry->b;
|
||||||
|
if (blendType != NOBLEND) {
|
||||||
|
if (hi4 == 15) entry = &(pal[0]);
|
||||||
|
else ++entry;
|
||||||
|
unsigned f2 = ((index & 0x0F) << 4) + 1; // +1 so we scale by 256 as a max value, then result can just be shifted by 8
|
||||||
|
unsigned f1 = (257 - f2); // f2 is 1 minimum, so this is 256 max
|
||||||
|
red1 = (red1 * f1 + (unsigned)entry->r * f2) >> 8;
|
||||||
|
green1 = (green1 * f1 + (unsigned)entry->g * f2) >> 8;
|
||||||
|
blue1 = (blue1 * f1 + (unsigned)entry->b * f2) >> 8;
|
||||||
|
}
|
||||||
|
if (brightness < 255) { // note: zero checking could be done to return black but that is hardly ever used so it is omitted
|
||||||
|
uint32_t scale = brightness + 1; // adjust for rounding (bitshift)
|
||||||
|
red1 = (red1 * scale) >> 8;
|
||||||
|
green1 = (green1 * scale) >> 8;
|
||||||
|
blue1 = (blue1 * scale) >> 8;
|
||||||
|
}
|
||||||
|
return RGBW32(red1,green1,blue1,0);
|
||||||
|
}
|
||||||
|
|
||||||
void setRandomColor(byte* rgb)
|
void setRandomColor(byte* rgb)
|
||||||
{
|
{
|
||||||
lastRandomIndex = get_random_wheel_index(lastRandomIndex);
|
lastRandomIndex = get_random_wheel_index(lastRandomIndex);
|
||||||
@ -103,91 +124,91 @@ void setRandomColor(byte* rgb)
|
|||||||
*/
|
*/
|
||||||
CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette)
|
CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette)
|
||||||
{
|
{
|
||||||
CHSV palettecolors[4]; //array of colors for the new palette
|
CHSV palettecolors[4]; // array of colors for the new palette
|
||||||
uint8_t keepcolorposition = random8(4); //color position of current random palette to keep
|
uint8_t keepcolorposition = hw_random8(4); // color position of current random palette to keep
|
||||||
palettecolors[keepcolorposition] = rgb2hsv_approximate(basepalette.entries[keepcolorposition*5]); //read one of the base colors of the current palette
|
palettecolors[keepcolorposition] = rgb2hsv(basepalette.entries[keepcolorposition*5]); // read one of the base colors of the current palette
|
||||||
palettecolors[keepcolorposition].hue += random8(10)-5; // +/- 5 randomness of base color
|
palettecolors[keepcolorposition].hue += hw_random8(10)-5; // +/- 5 randomness of base color
|
||||||
//generate 4 saturation and brightness value numbers
|
// generate 4 saturation and brightness value numbers
|
||||||
//only one saturation is allowed to be below 200 creating mostly vibrant colors
|
// only one saturation is allowed to be below 200 creating mostly vibrant colors
|
||||||
//only one brightness value number is allowed below 200, creating mostly bright palettes
|
// only one brightness value number is allowed below 200, creating mostly bright palettes
|
||||||
|
|
||||||
for (int i = 0; i < 3; i++) { //generate three high values
|
for (int i = 0; i < 3; i++) { // generate three high values
|
||||||
palettecolors[i].saturation = random8(200,255);
|
palettecolors[i].saturation = hw_random8(200,255);
|
||||||
palettecolors[i].value = random8(220,255);
|
palettecolors[i].value = hw_random8(220,255);
|
||||||
}
|
}
|
||||||
//allow one to be lower
|
// allow one to be lower
|
||||||
palettecolors[3].saturation = random8(20,255);
|
palettecolors[3].saturation = hw_random8(20,255);
|
||||||
palettecolors[3].value = random8(80,255);
|
palettecolors[3].value = hw_random8(80,255);
|
||||||
|
|
||||||
//shuffle the arrays
|
// shuffle the arrays
|
||||||
for (int i = 3; i > 0; i--) {
|
for (int i = 3; i > 0; i--) {
|
||||||
std::swap(palettecolors[i].saturation, palettecolors[random8(i + 1)].saturation);
|
std::swap(palettecolors[i].saturation, palettecolors[hw_random8(i + 1)].saturation);
|
||||||
std::swap(palettecolors[i].value, palettecolors[random8(i + 1)].value);
|
std::swap(palettecolors[i].value, palettecolors[hw_random8(i + 1)].value);
|
||||||
}
|
}
|
||||||
|
|
||||||
//now generate three new hues based off of the hue of the chosen current color
|
// now generate three new hues based off of the hue of the chosen current color
|
||||||
uint8_t basehue = palettecolors[keepcolorposition].hue;
|
uint8_t basehue = palettecolors[keepcolorposition].hue;
|
||||||
uint8_t harmonics[3]; //hues that are harmonic but still a little random
|
uint8_t harmonics[3]; // hues that are harmonic but still a little random
|
||||||
uint8_t type = random8(5); //choose a harmony type
|
uint8_t type = hw_random8(5); // choose a harmony type
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 0: // analogous
|
case 0: // analogous
|
||||||
harmonics[0] = basehue + random8(30, 50);
|
harmonics[0] = basehue + hw_random8(30, 50);
|
||||||
harmonics[1] = basehue + random8(10, 30);
|
harmonics[1] = basehue + hw_random8(10, 30);
|
||||||
harmonics[2] = basehue - random8(10, 30);
|
harmonics[2] = basehue - hw_random8(10, 30);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1: // triadic
|
case 1: // triadic
|
||||||
harmonics[0] = basehue + 113 + random8(15);
|
harmonics[0] = basehue + 113 + hw_random8(15);
|
||||||
harmonics[1] = basehue + 233 + random8(15);
|
harmonics[1] = basehue + 233 + hw_random8(15);
|
||||||
harmonics[2] = basehue - 7 + random8(15);
|
harmonics[2] = basehue - 7 + hw_random8(15);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2: // split-complementary
|
case 2: // split-complementary
|
||||||
harmonics[0] = basehue + 145 + random8(10);
|
harmonics[0] = basehue + 145 + hw_random8(10);
|
||||||
harmonics[1] = basehue + 205 + random8(10);
|
harmonics[1] = basehue + 205 + hw_random8(10);
|
||||||
harmonics[2] = basehue - 5 + random8(10);
|
harmonics[2] = basehue - 5 + hw_random8(10);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 3: // square
|
case 3: // square
|
||||||
harmonics[0] = basehue + 85 + random8(10);
|
harmonics[0] = basehue + 85 + hw_random8(10);
|
||||||
harmonics[1] = basehue + 175 + random8(10);
|
harmonics[1] = basehue + 175 + hw_random8(10);
|
||||||
harmonics[2] = basehue + 265 + random8(10);
|
harmonics[2] = basehue + 265 + hw_random8(10);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 4: // tetradic
|
case 4: // tetradic
|
||||||
harmonics[0] = basehue + 80 + random8(20);
|
harmonics[0] = basehue + 80 + hw_random8(20);
|
||||||
harmonics[1] = basehue + 170 + random8(20);
|
harmonics[1] = basehue + 170 + hw_random8(20);
|
||||||
harmonics[2] = basehue - 15 + random8(30);
|
harmonics[2] = basehue - 15 + hw_random8(30);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (random8() < 128) {
|
if (hw_random8() < 128) {
|
||||||
//50:50 chance of shuffling hues or keep the color order
|
// 50:50 chance of shuffling hues or keep the color order
|
||||||
for (int i = 2; i > 0; i--) {
|
for (int i = 2; i > 0; i--) {
|
||||||
std::swap(harmonics[i], harmonics[random8(i + 1)]);
|
std::swap(harmonics[i], harmonics[hw_random8(i + 1)]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//now set the hues
|
// now set the hues
|
||||||
int j = 0;
|
int j = 0;
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
if (i==keepcolorposition) continue; //skip the base color
|
if (i==keepcolorposition) continue; // skip the base color
|
||||||
palettecolors[i].hue = harmonics[j];
|
palettecolors[i].hue = harmonics[j];
|
||||||
j++;
|
j++;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool makepastelpalette = false;
|
bool makepastelpalette = false;
|
||||||
if (random8() < 25) { //~10% chance of desaturated 'pastel' colors
|
if (hw_random8() < 25) { // ~10% chance of desaturated 'pastel' colors
|
||||||
makepastelpalette = true;
|
makepastelpalette = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//apply saturation & gamma correction
|
// apply saturation & gamma correction
|
||||||
CRGB RGBpalettecolors[4];
|
CRGB RGBpalettecolors[4];
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
if (makepastelpalette && palettecolors[i].saturation > 180) {
|
if (makepastelpalette && palettecolors[i].saturation > 180) {
|
||||||
palettecolors[i].saturation -= 160; //desaturate all four colors
|
palettecolors[i].saturation -= 160; //desaturate all four colors
|
||||||
}
|
}
|
||||||
RGBpalettecolors[i] = (CRGB)palettecolors[i]; //convert to RGB
|
RGBpalettecolors[i] = (CRGB)palettecolors[i]; //convert to RGB
|
||||||
RGBpalettecolors[i] = gamma32(((uint32_t)RGBpalettecolors[i]) & 0x00FFFFFFU); //strip alpha from CRGB
|
RGBpalettecolors[i] = gamma32(((uint32_t)RGBpalettecolors[i]) & 0x00FFFFFFU); //strip alpha from CRGB
|
||||||
}
|
}
|
||||||
@ -198,34 +219,72 @@ CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette)
|
|||||||
RGBpalettecolors[3]);
|
RGBpalettecolors[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
CRGBPalette16 generateRandomPalette() //generate fully random palette
|
CRGBPalette16 generateRandomPalette() // generate fully random palette
|
||||||
{
|
{
|
||||||
return CRGBPalette16(CHSV(random8(), random8(160, 255), random8(128, 255)),
|
return CRGBPalette16(CHSV(hw_random8(), hw_random8(160, 255), hw_random8(128, 255)),
|
||||||
CHSV(random8(), random8(160, 255), random8(128, 255)),
|
CHSV(hw_random8(), hw_random8(160, 255), hw_random8(128, 255)),
|
||||||
CHSV(random8(), random8(160, 255), random8(128, 255)),
|
CHSV(hw_random8(), hw_random8(160, 255), hw_random8(128, 255)),
|
||||||
CHSV(random8(), random8(160, 255), random8(128, 255)));
|
CHSV(hw_random8(), hw_random8(160, 255), hw_random8(128, 255)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void colorHStoRGB(uint16_t hue, byte sat, byte* rgb) //hue, sat to rgb
|
void hsv2rgb(const CHSV32& hsv, uint32_t& rgb) // convert HSV (16bit hue) to RGB (32bit with white = 0)
|
||||||
{
|
{
|
||||||
float h = ((float)hue)/10922.5f; // hue*6/65535
|
unsigned int remainder, region, p, q, t;
|
||||||
float s = ((float)sat)/255.0f;
|
unsigned int h = hsv.h;
|
||||||
int i = int(h);
|
unsigned int s = hsv.s;
|
||||||
float f = h - i;
|
unsigned int v = hsv.v;
|
||||||
int p = int(255.0f * (1.0f-s));
|
if (s == 0) {
|
||||||
int q = int(255.0f * (1.0f-s*f));
|
rgb = v << 16 | v << 8 | v;
|
||||||
int t = int(255.0f * (1.0f-s*(1.0f-f)));
|
return;
|
||||||
p = constrain(p, 0, 255);
|
|
||||||
q = constrain(q, 0, 255);
|
|
||||||
t = constrain(t, 0, 255);
|
|
||||||
switch (i%6) {
|
|
||||||
case 0: rgb[0]=255,rgb[1]=t, rgb[2]=p; break;
|
|
||||||
case 1: rgb[0]=q, rgb[1]=255,rgb[2]=p; break;
|
|
||||||
case 2: rgb[0]=p, rgb[1]=255,rgb[2]=t; break;
|
|
||||||
case 3: rgb[0]=p, rgb[1]=q, rgb[2]=255;break;
|
|
||||||
case 4: rgb[0]=t, rgb[1]=p, rgb[2]=255;break;
|
|
||||||
case 5: rgb[0]=255,rgb[1]=p, rgb[2]=q; break;
|
|
||||||
}
|
}
|
||||||
|
region = h / 10923; // 65536 / 6 = 10923
|
||||||
|
remainder = (h - (region * 10923)) * 6;
|
||||||
|
p = (v * (255 - s)) >> 8;
|
||||||
|
q = (v * (255 - ((s * remainder) >> 16))) >> 8;
|
||||||
|
t = (v * (255 - ((s * (65535 - remainder)) >> 16))) >> 8;
|
||||||
|
switch (region) {
|
||||||
|
case 0:
|
||||||
|
rgb = v << 16 | t << 8 | p; break;
|
||||||
|
case 1:
|
||||||
|
rgb = q << 16 | v << 8 | p; break;
|
||||||
|
case 2:
|
||||||
|
rgb = p << 16 | v << 8 | t; break;
|
||||||
|
case 3:
|
||||||
|
rgb = p << 16 | q << 8 | v; break;
|
||||||
|
case 4:
|
||||||
|
rgb = t << 16 | p << 8 | v; break;
|
||||||
|
default:
|
||||||
|
rgb = v << 16 | p << 8 | q; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void rgb2hsv(const uint32_t rgb, CHSV32& hsv) // convert RGB to HSV (16bit hue), much more accurate and faster than fastled version
|
||||||
|
{
|
||||||
|
hsv.raw = 0;
|
||||||
|
int32_t r = (rgb>>16)&0xFF;
|
||||||
|
int32_t g = (rgb>>8)&0xFF;
|
||||||
|
int32_t b = rgb&0xFF;
|
||||||
|
int32_t minval, maxval, delta;
|
||||||
|
minval = min(r, g);
|
||||||
|
minval = min(minval, b);
|
||||||
|
maxval = max(r, g);
|
||||||
|
maxval = max(maxval, b);
|
||||||
|
if (maxval == 0) return; // black
|
||||||
|
hsv.v = maxval;
|
||||||
|
delta = maxval - minval;
|
||||||
|
hsv.s = (255 * delta) / maxval;
|
||||||
|
if (hsv.s == 0) return; // gray value
|
||||||
|
if (maxval == r) hsv.h = (10923 * (g - b)) / delta;
|
||||||
|
else if (maxval == g) hsv.h = 21845 + (10923 * (b - r)) / delta;
|
||||||
|
else hsv.h = 43690 + (10923 * (r - g)) / delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
void colorHStoRGB(uint16_t hue, byte sat, byte* rgb) { //hue, sat to rgb
|
||||||
|
uint32_t crgb;
|
||||||
|
hsv2rgb(CHSV32(hue, sat, 255), crgb);
|
||||||
|
rgb[0] = byte((crgb) >> 16);
|
||||||
|
rgb[1] = byte((crgb) >> 8);
|
||||||
|
rgb[2] = byte(crgb);
|
||||||
}
|
}
|
||||||
|
|
||||||
//get RGB values from color temperature in K (https://tannerhelland.com/2012/09/18/convert-temperature-rgb-algorithm-code.html)
|
//get RGB values from color temperature in K (https://tannerhelland.com/2012/09/18/convert-temperature-rgb-algorithm-code.html)
|
||||||
@ -452,24 +511,8 @@ uint16_t approximateKelvinFromRGB(uint32_t rgb) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//gamma 2.8 lookup table used for color correction
|
// gamma lookup table used for color correction (filled on 1st use (cfg.cpp & set.cpp))
|
||||||
uint8_t NeoGammaWLEDMethod::gammaT[256] = {
|
uint8_t NeoGammaWLEDMethod::gammaT[256];
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5,
|
|
||||||
5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10,
|
|
||||||
10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16,
|
|
||||||
17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 24, 24, 25,
|
|
||||||
25, 26, 27, 27, 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 35, 36,
|
|
||||||
37, 38, 39, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 50,
|
|
||||||
51, 52, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 66, 67, 68,
|
|
||||||
69, 70, 72, 73, 74, 75, 77, 78, 79, 81, 82, 83, 85, 86, 87, 89,
|
|
||||||
90, 92, 93, 95, 96, 98, 99,101,102,104,105,107,109,110,112,114,
|
|
||||||
115,117,119,120,122,124,126,127,129,131,133,135,137,138,140,142,
|
|
||||||
144,146,148,150,152,154,156,158,160,162,164,167,169,171,173,175,
|
|
||||||
177,180,182,184,186,189,191,193,196,198,200,203,205,208,210,213,
|
|
||||||
215,218,220,223,225,228,231,233,236,239,241,244,247,249,252,255 };
|
|
||||||
|
|
||||||
// re-calculates & fills gamma table
|
// re-calculates & fills gamma table
|
||||||
void NeoGammaWLEDMethod::calcGammaTable(float gamma)
|
void NeoGammaWLEDMethod::calcGammaTable(float gamma)
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* Readability defines and their associated numerical values + compile-time constants
|
* Readability defines and their associated numerical values + compile-time constants
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define GRADIENT_PALETTE_COUNT 58
|
#define GRADIENT_PALETTE_COUNT 59
|
||||||
|
|
||||||
// You can define custom product info from build flags.
|
// You can define custom product info from build flags.
|
||||||
// This is useful to allow API consumer to identify what type of WLED version
|
// This is useful to allow API consumer to identify what type of WLED version
|
||||||
|
@ -761,7 +761,7 @@ Swap: <select id="xw${s}" name="XW${s}">
|
|||||||
Enable automatic brightness limiter: <input type="checkbox" name="ABL" onchange="enABL()"><br>
|
Enable automatic brightness limiter: <input type="checkbox" name="ABL" onchange="enABL()"><br>
|
||||||
<div id="abl">
|
<div id="abl">
|
||||||
<i>Automatically limits brightness to stay close to the limit.<br>
|
<i>Automatically limits brightness to stay close to the limit.<br>
|
||||||
Keep at <1A if poweing LEDs directly from the ESP 5V pin!<br>
|
Keep at <1A if powering LEDs directly from the ESP 5V pin!<br>
|
||||||
If using multiple outputs it is recommended to use per-output limiter.<br>
|
If using multiple outputs it is recommended to use per-output limiter.<br>
|
||||||
Analog (PWM) and virtual LEDs cannot use automatic brightness limiter.<br></i>
|
Analog (PWM) and virtual LEDs cannot use automatic brightness limiter.<br></i>
|
||||||
<div id="psuMA">Maximum PSU Current: <input name="MA" type="number" class="xl" min="250" max="65000" oninput="UI()" required> mA<br></div>
|
<div id="psuMA">Maximum PSU Current: <input name="MA" type="number" class="xl" min="250" max="65000" oninput="UI()" required> mA<br></div>
|
||||||
|
@ -39,6 +39,7 @@ void handleDDPPacket(e131_packet_t* p) {
|
|||||||
realtimeLock(realtimeTimeoutMs, REALTIME_MODE_DDP);
|
realtimeLock(realtimeTimeoutMs, REALTIME_MODE_DDP);
|
||||||
|
|
||||||
if (!realtimeOverride || (realtimeMode && useMainSegmentOnly)) {
|
if (!realtimeOverride || (realtimeMode && useMainSegmentOnly)) {
|
||||||
|
if (useMainSegmentOnly) strip.getMainSegment().beginDraw();
|
||||||
for (unsigned i = start; i < stop; i++, c += ddpChannelsPerLed) {
|
for (unsigned i = start; i < stop; i++, c += ddpChannelsPerLed) {
|
||||||
setRealtimePixel(i, data[c], data[c+1], data[c+2], ddpChannelsPerLed >3 ? data[c+3] : 0);
|
setRealtimePixel(i, data[c], data[c+1], data[c+2], ddpChannelsPerLed >3 ? data[c+3] : 0);
|
||||||
}
|
}
|
||||||
@ -147,6 +148,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){
|
|||||||
if (realtimeOverride && !(realtimeMode && useMainSegmentOnly)) return;
|
if (realtimeOverride && !(realtimeMode && useMainSegmentOnly)) return;
|
||||||
|
|
||||||
wChannel = (availDMXLen > 3) ? e131_data[dataOffset+3] : 0;
|
wChannel = (availDMXLen > 3) ? e131_data[dataOffset+3] : 0;
|
||||||
|
if (useMainSegmentOnly) strip.getMainSegment().beginDraw();
|
||||||
for (unsigned i = 0; i < totalLen; i++)
|
for (unsigned i = 0; i < totalLen; i++)
|
||||||
setRealtimePixel(i, e131_data[dataOffset+0], e131_data[dataOffset+1], e131_data[dataOffset+2], wChannel);
|
setRealtimePixel(i, e131_data[dataOffset+0], e131_data[dataOffset+1], e131_data[dataOffset+2], wChannel);
|
||||||
break;
|
break;
|
||||||
@ -164,6 +166,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){
|
|||||||
strip.setBrightness(bri, true);
|
strip.setBrightness(bri, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (useMainSegmentOnly) strip.getMainSegment().beginDraw();
|
||||||
for (unsigned i = 0; i < totalLen; i++)
|
for (unsigned i = 0; i < totalLen; i++)
|
||||||
setRealtimePixel(i, e131_data[dataOffset+1], e131_data[dataOffset+2], e131_data[dataOffset+3], wChannel);
|
setRealtimePixel(i, e131_data[dataOffset+1], e131_data[dataOffset+2], e131_data[dataOffset+3], wChannel);
|
||||||
break;
|
break;
|
||||||
@ -308,6 +311,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (useMainSegmentOnly) strip.getMainSegment().beginDraw();
|
||||||
if (!is4Chan) {
|
if (!is4Chan) {
|
||||||
for (unsigned i = previousLeds; i < ledsTotal; i++) {
|
for (unsigned i = previousLeds; i < ledsTotal; i++) {
|
||||||
setRealtimePixel(i, e131_data[dmxOffset], e131_data[dmxOffset+1], e131_data[dmxOffset+2], 0);
|
setRealtimePixel(i, e131_data[dmxOffset], e131_data[dmxOffset+1], e131_data[dmxOffset+2], 0);
|
||||||
|
@ -66,6 +66,89 @@ typedef struct WiFiConfig {
|
|||||||
} wifi_config;
|
} wifi_config;
|
||||||
|
|
||||||
//colors.cpp
|
//colors.cpp
|
||||||
|
#define ColorFromPalette ColorFromPaletteWLED // override fastled version
|
||||||
|
|
||||||
|
// CRGBW can be used to manipulate 32bit colors faster. However: if it is passed to functions, it adds overhead compared to a uint32_t color
|
||||||
|
// use with caution and pay attention to flash size. Usually converting a uint32_t to CRGBW to extract r, g, b, w values is slower than using bitshifts
|
||||||
|
// it can be useful to avoid back and forth conversions between uint32_t and fastled CRGB
|
||||||
|
struct CRGBW {
|
||||||
|
union {
|
||||||
|
uint32_t color32; // Access as a 32-bit value (0xWWRRGGBB)
|
||||||
|
struct {
|
||||||
|
uint8_t b;
|
||||||
|
uint8_t g;
|
||||||
|
uint8_t r;
|
||||||
|
uint8_t w;
|
||||||
|
};
|
||||||
|
uint8_t raw[4]; // Access as an array in the order B, G, R, W
|
||||||
|
};
|
||||||
|
|
||||||
|
// Default constructor
|
||||||
|
inline CRGBW() __attribute__((always_inline)) = default;
|
||||||
|
|
||||||
|
// Constructor from a 32-bit color (0xWWRRGGBB)
|
||||||
|
constexpr CRGBW(uint32_t color) __attribute__((always_inline)) : color32(color) {}
|
||||||
|
|
||||||
|
// Constructor with r, g, b, w values
|
||||||
|
constexpr CRGBW(uint8_t red, uint8_t green, uint8_t blue, uint8_t white = 0) __attribute__((always_inline)) : b(blue), g(green), r(red), w(white) {}
|
||||||
|
|
||||||
|
// Constructor from CRGB
|
||||||
|
constexpr CRGBW(CRGB rgb) __attribute__((always_inline)) : b(rgb.b), g(rgb.g), r(rgb.r), w(0) {}
|
||||||
|
|
||||||
|
// Access as an array
|
||||||
|
inline const uint8_t& operator[] (uint8_t x) const __attribute__((always_inline)) { return raw[x]; }
|
||||||
|
|
||||||
|
// Assignment from 32-bit color
|
||||||
|
inline CRGBW& operator=(uint32_t color) __attribute__((always_inline)) { color32 = color; return *this; }
|
||||||
|
|
||||||
|
// Assignment from r, g, b, w
|
||||||
|
inline CRGBW& operator=(const CRGB& rgb) __attribute__((always_inline)) { b = rgb.b; g = rgb.g; r = rgb.r; w = 0; return *this; }
|
||||||
|
|
||||||
|
// Conversion operator to uint32_t
|
||||||
|
inline operator uint32_t() const __attribute__((always_inline)) {
|
||||||
|
return color32;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
// Conversion operator to CRGB
|
||||||
|
inline operator CRGB() const __attribute__((always_inline)) {
|
||||||
|
return CRGB(r, g, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
CRGBW& scale32 (uint8_t scaledown) // 32bit math
|
||||||
|
{
|
||||||
|
if (color32 == 0) return *this; // 2 extra instructions, worth it if called a lot on black (which probably is true) adding check if scaledown is zero adds much more overhead as its 8bit
|
||||||
|
uint32_t scale = scaledown + 1;
|
||||||
|
uint32_t rb = (((color32 & 0x00FF00FF) * scale) >> 8) & 0x00FF00FF; // scale red and blue
|
||||||
|
uint32_t wg = (((color32 & 0xFF00FF00) >> 8) * scale) & 0xFF00FF00; // scale white and green
|
||||||
|
color32 = rb | wg;
|
||||||
|
return *this;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CHSV32 { // 32bit HSV color with 16bit hue for more accurate conversions
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
uint16_t h; // hue
|
||||||
|
uint8_t s; // saturation
|
||||||
|
uint8_t v; // value
|
||||||
|
};
|
||||||
|
uint32_t raw; // 32bit access
|
||||||
|
};
|
||||||
|
inline CHSV32() __attribute__((always_inline)) = default; // default constructor
|
||||||
|
|
||||||
|
/// Allow construction from hue, saturation, and value
|
||||||
|
/// @param ih input hue
|
||||||
|
/// @param is input saturation
|
||||||
|
/// @param iv input value
|
||||||
|
inline CHSV32(uint16_t ih, uint8_t is, uint8_t iv) __attribute__((always_inline)) // constructor from 16bit h, s, v
|
||||||
|
: h(ih), s(is), v(iv) {}
|
||||||
|
inline CHSV32(uint8_t ih, uint8_t is, uint8_t iv) __attribute__((always_inline)) // constructor from 8bit h, s, v
|
||||||
|
: h((uint16_t)ih << 8), s(is), v(iv) {}
|
||||||
|
inline CHSV32(const CHSV& chsv) __attribute__((always_inline)) // constructor from CHSV
|
||||||
|
: h((uint16_t)chsv.h << 8), s(chsv.s), v(chsv.v) {}
|
||||||
|
inline operator CHSV() const { return CHSV((uint8_t)(h >> 8), s, v); } // typecast to CHSV
|
||||||
|
};
|
||||||
// similar to NeoPixelBus NeoGammaTableMethod but allows dynamic changes (superseded by NPB::NeoGammaDynamicTableMethod)
|
// similar to NeoPixelBus NeoGammaTableMethod but allows dynamic changes (superseded by NPB::NeoGammaDynamicTableMethod)
|
||||||
class NeoGammaWLEDMethod {
|
class NeoGammaWLEDMethod {
|
||||||
public:
|
public:
|
||||||
@ -78,13 +161,18 @@ class NeoGammaWLEDMethod {
|
|||||||
};
|
};
|
||||||
#define gamma32(c) NeoGammaWLEDMethod::Correct32(c)
|
#define gamma32(c) NeoGammaWLEDMethod::Correct32(c)
|
||||||
#define gamma8(c) NeoGammaWLEDMethod::rawGamma8(c)
|
#define gamma8(c) NeoGammaWLEDMethod::rawGamma8(c)
|
||||||
[[gnu::hot]] uint32_t color_blend(uint32_t,uint32_t,uint16_t,bool b16=false);
|
[[gnu::hot]] uint32_t color_blend(uint32_t c1, uint32_t c2 , uint8_t blend);
|
||||||
[[gnu::hot]] uint32_t color_add(uint32_t,uint32_t, bool fast=false);
|
inline uint32_t color_blend16(uint32_t c1, uint32_t c2, uint16_t b) { return color_blend(c1, c2, b >> 8); };
|
||||||
|
[[gnu::hot]] uint32_t color_add(uint32_t, uint32_t, bool preserveCR = false);
|
||||||
[[gnu::hot]] uint32_t color_fade(uint32_t c1, uint8_t amount, bool video=false);
|
[[gnu::hot]] uint32_t color_fade(uint32_t c1, uint8_t amount, bool video=false);
|
||||||
|
[[gnu::hot]] uint32_t ColorFromPaletteWLED(const CRGBPalette16 &pal, unsigned index, uint8_t brightness = (uint8_t)255U, TBlendType blendType = LINEARBLEND);
|
||||||
CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette);
|
CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette);
|
||||||
CRGBPalette16 generateRandomPalette();
|
CRGBPalette16 generateRandomPalette();
|
||||||
inline uint32_t colorFromRgbw(byte* rgbw) { return uint32_t((byte(rgbw[3]) << 24) | (byte(rgbw[0]) << 16) | (byte(rgbw[1]) << 8) | (byte(rgbw[2]))); }
|
inline uint32_t colorFromRgbw(byte* rgbw) { return uint32_t((byte(rgbw[3]) << 24) | (byte(rgbw[0]) << 16) | (byte(rgbw[1]) << 8) | (byte(rgbw[2]))); }
|
||||||
void colorHStoRGB(uint16_t hue, byte sat, byte* rgb); //hue, sat to rgb
|
void hsv2rgb(const CHSV32& hsv, uint32_t& rgb);
|
||||||
|
void colorHStoRGB(uint16_t hue, byte sat, byte* rgb);
|
||||||
|
void rgb2hsv(const uint32_t rgb, CHSV32& hsv);
|
||||||
|
inline CHSV rgb2hsv(const CRGB c) { CHSV32 hsv; rgb2hsv((uint32_t((byte(c.r) << 16) | (byte(c.g) << 8) | (byte(c.b)))), hsv); return CHSV(hsv); } // CRGB to hsv
|
||||||
void colorKtoRGB(uint16_t kelvin, byte* rgb);
|
void colorKtoRGB(uint16_t kelvin, byte* rgb);
|
||||||
void colorCTtoRGB(uint16_t mired, byte* rgb); //white spectrum to rgb
|
void colorCTtoRGB(uint16_t mired, byte* rgb); //white spectrum to rgb
|
||||||
void colorXYtoRGB(float x, float y, byte* rgb); // only defined if huesync disabled TODO
|
void colorXYtoRGB(float x, float y, byte* rgb); // only defined if huesync disabled TODO
|
||||||
@ -370,6 +458,12 @@ void userConnected();
|
|||||||
void userLoop();
|
void userLoop();
|
||||||
|
|
||||||
//util.cpp
|
//util.cpp
|
||||||
|
#ifdef ESP8266
|
||||||
|
#define HW_RND_REGISTER RANDOM_REG32
|
||||||
|
#else // ESP32 family
|
||||||
|
#include "soc/wdev_reg.h"
|
||||||
|
#define HW_RND_REGISTER REG_READ(WDEV_RND_REG)
|
||||||
|
#endif
|
||||||
int getNumVal(const String* req, uint16_t pos);
|
int getNumVal(const String* req, uint16_t pos);
|
||||||
void parseNumber(const char* str, byte* val, byte minv=0, byte maxv=255);
|
void parseNumber(const char* str, byte* val, byte minv=0, byte maxv=255);
|
||||||
bool getVal(JsonVariant elem, byte* val, byte minv=0, byte maxv=255); // getVal supports inc/decrementing and random ("X~Y(r|~[w][-][Z])" form)
|
bool getVal(JsonVariant elem, byte* val, byte minv=0, byte maxv=255); // getVal supports inc/decrementing and random ("X~Y(r|~[w][-][Z])" form)
|
||||||
@ -397,6 +491,23 @@ void enumerateLedmaps();
|
|||||||
uint8_t get_random_wheel_index(uint8_t pos);
|
uint8_t get_random_wheel_index(uint8_t pos);
|
||||||
float mapf(float x, float in_min, float in_max, float out_min, float out_max);
|
float mapf(float x, float in_min, float in_max, float out_min, float out_max);
|
||||||
|
|
||||||
|
// fast (true) random numbers using hardware RNG, all functions return values in the range lowerlimit to upperlimit-1
|
||||||
|
// note: for true random numbers with high entropy, do not call faster than every 200ns (5MHz)
|
||||||
|
// tests show it is still highly random reading it quickly in a loop (better than fastled PRNG)
|
||||||
|
// for 8bit and 16bit random functions: no limit check is done for best speed
|
||||||
|
// 32bit inputs are used for speed and code size, limits don't work if inverted or out of range
|
||||||
|
// inlining does save code size except for random(a,b) and 32bit random with limits
|
||||||
|
#define random hw_random // replace arduino random()
|
||||||
|
inline uint32_t hw_random() { return HW_RND_REGISTER; };
|
||||||
|
uint32_t hw_random(uint32_t upperlimit); // not inlined for code size
|
||||||
|
int32_t hw_random(int32_t lowerlimit, int32_t upperlimit);
|
||||||
|
inline uint16_t hw_random16() { return HW_RND_REGISTER; };
|
||||||
|
inline uint16_t hw_random16(uint32_t upperlimit) { return (hw_random16() * upperlimit) >> 16; }; // input range 0-65535 (uint16_t)
|
||||||
|
inline int16_t hw_random16(int32_t lowerlimit, int32_t upperlimit) { int32_t range = upperlimit - lowerlimit; return lowerlimit + hw_random16(range); }; // signed limits, use int16_t ranges
|
||||||
|
inline uint8_t hw_random8() { return HW_RND_REGISTER; };
|
||||||
|
inline uint8_t hw_random8(uint32_t upperlimit) { return (hw_random8() * upperlimit) >> 8; }; // input range 0-255
|
||||||
|
inline uint8_t hw_random8(uint32_t lowerlimit, uint32_t upperlimit) { uint32_t range = upperlimit - lowerlimit; return lowerlimit + hw_random8(range); }; // input range 0-255
|
||||||
|
|
||||||
// RAII guard class for the JSON Buffer lock
|
// RAII guard class for the JSON Buffer lock
|
||||||
// Modeled after std::lock_guard
|
// Modeled after std::lock_guard
|
||||||
class JSONBufferGuard {
|
class JSONBufferGuard {
|
||||||
|
@ -129,7 +129,7 @@ static void changeEffectSpeed(int8_t amount)
|
|||||||
} else { // if Effect == "solid Color", change the hue of the primary color
|
} else { // if Effect == "solid Color", change the hue of the primary color
|
||||||
Segment& sseg = irApplyToAllSelected ? strip.getFirstSelectedSeg() : strip.getMainSegment();
|
Segment& sseg = irApplyToAllSelected ? strip.getFirstSelectedSeg() : strip.getMainSegment();
|
||||||
CRGB fastled_col = CRGB(sseg.colors[0]);
|
CRGB fastled_col = CRGB(sseg.colors[0]);
|
||||||
CHSV prim_hsv = rgb2hsv_approximate(fastled_col);
|
CHSV prim_hsv = rgb2hsv(fastled_col);
|
||||||
int16_t new_val = (int16_t)prim_hsv.h + amount;
|
int16_t new_val = (int16_t)prim_hsv.h + amount;
|
||||||
if (new_val > 255) new_val -= 255; // roll-over if bigger than 255
|
if (new_val > 255) new_val -= 255; // roll-over if bigger than 255
|
||||||
if (new_val < 0) new_val += 255; // roll-over if smaller than 0
|
if (new_val < 0) new_val += 255; // roll-over if smaller than 0
|
||||||
@ -173,7 +173,7 @@ static void changeEffectIntensity(int8_t amount)
|
|||||||
} else { // if Effect == "solid Color", change the saturation of the primary color
|
} else { // if Effect == "solid Color", change the saturation of the primary color
|
||||||
Segment& sseg = irApplyToAllSelected ? strip.getFirstSelectedSeg() : strip.getMainSegment();
|
Segment& sseg = irApplyToAllSelected ? strip.getFirstSelectedSeg() : strip.getMainSegment();
|
||||||
CRGB fastled_col = CRGB(sseg.colors[0]);
|
CRGB fastled_col = CRGB(sseg.colors[0]);
|
||||||
CHSV prim_hsv = rgb2hsv_approximate(fastled_col);
|
CHSV prim_hsv = rgb2hsv(fastled_col);
|
||||||
int16_t new_val = (int16_t) prim_hsv.s + amount;
|
int16_t new_val = (int16_t) prim_hsv.s + amount;
|
||||||
prim_hsv.s = (byte)constrain(new_val,0,255); // constrain to 0-255
|
prim_hsv.s = (byte)constrain(new_val,0,255); // constrain to 0-255
|
||||||
hsv2rgb_rainbow(prim_hsv, fastled_col);
|
hsv2rgb_rainbow(prim_hsv, fastled_col);
|
||||||
@ -435,7 +435,7 @@ static void decodeIR44(uint32_t code)
|
|||||||
case IR44_DIY2 : presetFallback(2, FX_MODE_BREATH, 0); break;
|
case IR44_DIY2 : presetFallback(2, FX_MODE_BREATH, 0); break;
|
||||||
case IR44_DIY3 : presetFallback(3, FX_MODE_FIRE_FLICKER, 0); break;
|
case IR44_DIY3 : presetFallback(3, FX_MODE_FIRE_FLICKER, 0); break;
|
||||||
case IR44_DIY4 : presetFallback(4, FX_MODE_RAINBOW, 0); break;
|
case IR44_DIY4 : presetFallback(4, FX_MODE_RAINBOW, 0); break;
|
||||||
case IR44_DIY5 : presetFallback(5, FX_MODE_METEOR_SMOOTH, 0); break;
|
case IR44_DIY5 : presetFallback(5, FX_MODE_METEOR, 0); break;
|
||||||
case IR44_DIY6 : presetFallback(6, FX_MODE_RAIN, 0); break;
|
case IR44_DIY6 : presetFallback(6, FX_MODE_RAIN, 0); break;
|
||||||
case IR44_AUTO : changeEffect(FX_MODE_STATIC); break;
|
case IR44_AUTO : changeEffect(FX_MODE_STATIC); break;
|
||||||
case IR44_FLASH : changeEffect(FX_MODE_PALETTE); break;
|
case IR44_FLASH : changeEffect(FX_MODE_PALETTE); break;
|
||||||
@ -593,7 +593,7 @@ static void decodeIRJson(uint32_t code)
|
|||||||
decBrightness();
|
decBrightness();
|
||||||
} else if (cmdStr.startsWith(F("!presetF"))) { //!presetFallback
|
} else if (cmdStr.startsWith(F("!presetF"))) { //!presetFallback
|
||||||
uint8_t p1 = fdo["PL"] | 1;
|
uint8_t p1 = fdo["PL"] | 1;
|
||||||
uint8_t p2 = fdo["FX"] | random8(strip.getModeCount() -1);
|
uint8_t p2 = fdo["FX"] | hw_random8(strip.getModeCount() -1);
|
||||||
uint8_t p3 = fdo["FP"] | 0;
|
uint8_t p3 = fdo["FP"] | 0;
|
||||||
presetFallback(p1, p2, p3);
|
presetFallback(p1, p2, p3);
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
|
|||||||
//DEBUG_PRINTLN(F("-- JSON deserialize segment."));
|
//DEBUG_PRINTLN(F("-- JSON deserialize segment."));
|
||||||
Segment& seg = strip.getSegment(id);
|
Segment& seg = strip.getSegment(id);
|
||||||
//DEBUG_PRINTF_P(PSTR("-- Original segment: %p (%p)\n"), &seg, seg.data);
|
//DEBUG_PRINTF_P(PSTR("-- Original segment: %p (%p)\n"), &seg, seg.data);
|
||||||
Segment prev = seg; //make a backup so we can tell if something changed (calling copy constructor)
|
const Segment prev = seg; //make a backup so we can tell if something changed (calling copy constructor)
|
||||||
//DEBUG_PRINTF_P(PSTR("-- Duplicate segment: %p (%p)\n"), &prev, prev.data);
|
//DEBUG_PRINTF_P(PSTR("-- Duplicate segment: %p (%p)\n"), &prev, prev.data);
|
||||||
|
|
||||||
int start = elem["start"] | seg.start;
|
int start = elem["start"] | seg.start;
|
||||||
@ -96,17 +96,11 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
|
|||||||
uint16_t of = seg.offset;
|
uint16_t of = seg.offset;
|
||||||
uint8_t soundSim = elem["si"] | seg.soundSim;
|
uint8_t soundSim = elem["si"] | seg.soundSim;
|
||||||
uint8_t map1D2D = elem["m12"] | seg.map1D2D;
|
uint8_t map1D2D = elem["m12"] | seg.map1D2D;
|
||||||
|
uint8_t set = elem[F("set")] | seg.set;
|
||||||
if ((spc>0 && spc!=seg.spacing) || seg.map1D2D!=map1D2D) seg.fill(BLACK); // clear spacing gaps
|
seg.set = constrain(set, 0, 3);
|
||||||
|
|
||||||
seg.map1D2D = constrain(map1D2D, 0, 7);
|
|
||||||
seg.soundSim = constrain(soundSim, 0, 3);
|
seg.soundSim = constrain(soundSim, 0, 3);
|
||||||
|
|
||||||
uint8_t set = elem[F("set")] | seg.set;
|
int len = (stop > start) ? stop - start : 1;
|
||||||
seg.set = constrain(set, 0, 3);
|
|
||||||
|
|
||||||
int len = 1;
|
|
||||||
if (stop > start) len = stop - start;
|
|
||||||
int offset = elem[F("of")] | INT32_MAX;
|
int offset = elem[F("of")] | INT32_MAX;
|
||||||
if (offset != INT32_MAX) {
|
if (offset != INT32_MAX) {
|
||||||
int offsetAbs = abs(offset);
|
int offsetAbs = abs(offset);
|
||||||
@ -117,7 +111,7 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
|
|||||||
if (stop > start && of > len -1) of = len -1;
|
if (stop > start && of > len -1) of = len -1;
|
||||||
|
|
||||||
// update segment (delete if necessary)
|
// update segment (delete if necessary)
|
||||||
seg.setUp(start, stop, grp, spc, of, startY, stopY); // strip needs to be suspended for this to work without issues
|
seg.setGeometry(start, stop, grp, spc, of, startY, stopY, map1D2D); // strip needs to be suspended for this to work without issues
|
||||||
|
|
||||||
if (newSeg) seg.refreshLightCapabilities(); // fix for #3403
|
if (newSeg) seg.refreshLightCapabilities(); // fix for #3403
|
||||||
|
|
||||||
|
@ -75,6 +75,7 @@ byte scaledBri(byte in)
|
|||||||
void applyBri() {
|
void applyBri() {
|
||||||
if (!realtimeMode || !arlsForceMaxBri)
|
if (!realtimeMode || !arlsForceMaxBri)
|
||||||
{
|
{
|
||||||
|
//DEBUG_PRINTF_P(PSTR("Applying strip brightness: %d (%d,%d)\n"), (int)briT, (int)bri, (int)briOld);
|
||||||
strip.setBrightness(scaledBri(briT));
|
strip.setBrightness(scaledBri(briT));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -139,7 +140,6 @@ void stateUpdated(byte callMode) {
|
|||||||
|
|
||||||
if (transitionActive) {
|
if (transitionActive) {
|
||||||
briOld = briT;
|
briOld = briT;
|
||||||
tperLast = 0;
|
|
||||||
} else
|
} else
|
||||||
strip.setTransitionMode(true); // force all segments to transition mode
|
strip.setTransitionMode(true); // force all segments to transition mode
|
||||||
transitionActive = true;
|
transitionActive = true;
|
||||||
@ -179,22 +179,21 @@ void handleTransitions()
|
|||||||
updateInterfaces(interfaceUpdateCallMode);
|
updateInterfaces(interfaceUpdateCallMode);
|
||||||
|
|
||||||
if (transitionActive && strip.getTransition() > 0) {
|
if (transitionActive && strip.getTransition() > 0) {
|
||||||
float tper = (millis() - transitionStartTime)/(float)strip.getTransition();
|
int ti = millis() - transitionStartTime;
|
||||||
if (tper >= 1.0f) {
|
int tr = strip.getTransition();
|
||||||
|
if (ti/tr) {
|
||||||
strip.setTransitionMode(false); // stop all transitions
|
strip.setTransitionMode(false); // stop all transitions
|
||||||
// restore (global) transition time if not called from UDP notifier or single/temporary transition from JSON (also playlist)
|
// restore (global) transition time if not called from UDP notifier or single/temporary transition from JSON (also playlist)
|
||||||
if (jsonTransitionOnce) strip.setTransition(transitionDelay);
|
if (jsonTransitionOnce) strip.setTransition(transitionDelay);
|
||||||
transitionActive = false;
|
transitionActive = false;
|
||||||
jsonTransitionOnce = false;
|
jsonTransitionOnce = false;
|
||||||
tperLast = 0;
|
|
||||||
applyFinalBri();
|
applyFinalBri();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (tper - tperLast < 0.004f) return; // less than 1 bit change (1/255)
|
byte briTO = briT;
|
||||||
tperLast = tper;
|
int deltaBri = (int)bri - (int)briOld;
|
||||||
briT = briOld + ((bri - briOld) * tper);
|
briT = briOld + (deltaBri * ti / tr);
|
||||||
|
if (briTO != briT) applyBri();
|
||||||
applyBri();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,8 +228,8 @@ void handleNightlight()
|
|||||||
colNlT[1] = effectSpeed;
|
colNlT[1] = effectSpeed;
|
||||||
colNlT[2] = effectPalette;
|
colNlT[2] = effectPalette;
|
||||||
|
|
||||||
strip.setMode(strip.getFirstSelectedSegId(), FX_MODE_STATIC); // make sure seg runtime is reset if it was in sunrise mode
|
strip.getFirstSelectedSeg().setMode(FX_MODE_STATIC); // make sure seg runtime is reset if it was in sunrise mode
|
||||||
effectCurrent = FX_MODE_SUNRISE;
|
effectCurrent = FX_MODE_SUNRISE; // colorUpdated() will take care of assigning that to all selected segments
|
||||||
effectSpeed = nightlightDelayMins;
|
effectSpeed = nightlightDelayMins;
|
||||||
effectPalette = 0;
|
effectPalette = 0;
|
||||||
if (effectSpeed > 60) effectSpeed = 60; //currently limited to 60 minutes
|
if (effectSpeed > 60) effectSpeed = 60; //currently limited to 60 minutes
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Color palettes for FastLED effects (65-73).
|
* Color palettes for FastLED effects (65-73).
|
||||||
|
* 4 bytes per color: index, red, green, blue
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// From ColorWavesWithPalettes by Mark Kriegsman: https://gist.github.com/kriegsman/8281905786e8b2632aeb
|
// From ColorWavesWithPalettes by Mark Kriegsman: https://gist.github.com/kriegsman/8281905786e8b2632aeb
|
||||||
@ -844,6 +845,12 @@ const byte candy2_gp[] PROGMEM = {
|
|||||||
211, 39, 33, 34,
|
211, 39, 33, 34,
|
||||||
255, 1, 1, 1};
|
255, 1, 1, 1};
|
||||||
|
|
||||||
|
const byte trafficlight_gp[] PROGMEM = {
|
||||||
|
0, 0, 0, 0, //black
|
||||||
|
85, 0, 255, 0, //green
|
||||||
|
170, 255, 255, 0, //yellow
|
||||||
|
255, 255, 0, 0}; //red
|
||||||
|
|
||||||
// array of fastled palettes (palette 6 - 12)
|
// array of fastled palettes (palette 6 - 12)
|
||||||
const TProgmemRGBPalette16 *const fastledPalettes[] PROGMEM = {
|
const TProgmemRGBPalette16 *const fastledPalettes[] PROGMEM = {
|
||||||
&PartyColors_p, //06-00 Party
|
&PartyColors_p, //06-00 Party
|
||||||
@ -917,7 +924,8 @@ const byte* const gGradientPalettes[] PROGMEM = {
|
|||||||
blink_red_gp, //67-54 Blink Red
|
blink_red_gp, //67-54 Blink Red
|
||||||
red_shift_gp, //68-55 Red Shift
|
red_shift_gp, //68-55 Red Shift
|
||||||
red_tide_gp, //69-56 Red Tide
|
red_tide_gp, //69-56 Red Tide
|
||||||
candy2_gp //70-57 Candy2
|
candy2_gp, //70-57 Candy2
|
||||||
|
trafficlight_gp //71-58 Traffic Light
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -146,7 +146,7 @@ static bool remoteJson(int button)
|
|||||||
parsed = true;
|
parsed = true;
|
||||||
} else if (cmdStr.startsWith(F("!presetF"))) { //!presetFallback
|
} else if (cmdStr.startsWith(F("!presetF"))) { //!presetFallback
|
||||||
uint8_t p1 = fdo["PL"] | 1;
|
uint8_t p1 = fdo["PL"] | 1;
|
||||||
uint8_t p2 = fdo["FX"] | random8(strip.getModeCount() -1);
|
uint8_t p2 = fdo["FX"] | hw_random8(strip.getModeCount() -1);
|
||||||
uint8_t p3 = fdo["FP"] | 0;
|
uint8_t p3 = fdo["FP"] | 0;
|
||||||
presetWithFallback(p1, p2, p3);
|
presetWithFallback(p1, p2, p3);
|
||||||
parsed = true;
|
parsed = true;
|
||||||
|
@ -319,13 +319,12 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
gammaCorrectBri = request->hasArg(F("GB"));
|
gammaCorrectBri = request->hasArg(F("GB"));
|
||||||
gammaCorrectCol = request->hasArg(F("GC"));
|
gammaCorrectCol = request->hasArg(F("GC"));
|
||||||
gammaCorrectVal = request->arg(F("GV")).toFloat();
|
gammaCorrectVal = request->arg(F("GV")).toFloat();
|
||||||
if (gammaCorrectVal > 1.0f && gammaCorrectVal <= 3)
|
if (gammaCorrectVal <= 1.0f || gammaCorrectVal > 3) {
|
||||||
NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal);
|
|
||||||
else {
|
|
||||||
gammaCorrectVal = 1.0f; // no gamma correction
|
gammaCorrectVal = 1.0f; // no gamma correction
|
||||||
gammaCorrectBri = false;
|
gammaCorrectBri = false;
|
||||||
gammaCorrectCol = false;
|
gammaCorrectCol = false;
|
||||||
}
|
}
|
||||||
|
NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal); // fill look-up table
|
||||||
|
|
||||||
fadeTransition = request->hasArg(F("TF"));
|
fadeTransition = request->hasArg(F("TF"));
|
||||||
modeBlending = request->hasArg(F("EB"));
|
modeBlending = request->hasArg(F("EB"));
|
||||||
@ -839,8 +838,9 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// temporary values, write directly to segments, globals are updated by setValuesFromFirstSelectedSeg()
|
// temporary values, write directly to segments, globals are updated by setValuesFromFirstSelectedSeg()
|
||||||
uint32_t col0 = selseg.colors[0];
|
uint32_t col0 = selseg.colors[0];
|
||||||
uint32_t col1 = selseg.colors[1];
|
uint32_t col1 = selseg.colors[1];
|
||||||
|
uint32_t col2 = selseg.colors[2];
|
||||||
byte colIn[4] = {R(col0), G(col0), B(col0), W(col0)};
|
byte colIn[4] = {R(col0), G(col0), B(col0), W(col0)};
|
||||||
byte colInSec[4] = {R(col1), G(col1), B(col1), W(col1)};
|
byte colInSec[4] = {R(col1), G(col1), B(col1), W(col1)};
|
||||||
byte effectIn = selseg.mode;
|
byte effectIn = selseg.mode;
|
||||||
@ -875,7 +875,9 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
|||||||
if (pos > 0) {
|
if (pos > 0) {
|
||||||
spcI = std::max(0,getNumVal(&req, pos));
|
spcI = std::max(0,getNumVal(&req, pos));
|
||||||
}
|
}
|
||||||
strip.setSegment(selectedSeg, startI, stopI, grpI, spcI, UINT16_MAX, startY, stopY);
|
strip.suspend(); // must suspend strip operations before changing geometry
|
||||||
|
selseg.setGeometry(startI, stopI, grpI, spcI, UINT16_MAX, startY, stopY, selseg.map1D2D);
|
||||||
|
strip.resume();
|
||||||
|
|
||||||
pos = req.indexOf(F("RV=")); //Segment reverse
|
pos = req.indexOf(F("RV=")); //Segment reverse
|
||||||
if (pos > 0) selseg.reverse = req.charAt(pos+3) != '0';
|
if (pos > 0) selseg.reverse = req.charAt(pos+3) != '0';
|
||||||
@ -921,7 +923,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
|||||||
//set brightness
|
//set brightness
|
||||||
updateVal(req.c_str(), "&A=", &bri);
|
updateVal(req.c_str(), "&A=", &bri);
|
||||||
|
|
||||||
bool col0Changed = false, col1Changed = false;
|
bool col0Changed = false, col1Changed = false, col2Changed = false;
|
||||||
//set colors
|
//set colors
|
||||||
col0Changed |= updateVal(req.c_str(), "&R=", &colIn[0]);
|
col0Changed |= updateVal(req.c_str(), "&R=", &colIn[0]);
|
||||||
col0Changed |= updateVal(req.c_str(), "&G=", &colIn[1]);
|
col0Changed |= updateVal(req.c_str(), "&G=", &colIn[1]);
|
||||||
@ -978,7 +980,6 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
|||||||
}
|
}
|
||||||
|
|
||||||
//set color from HEX or 32bit DEC
|
//set color from HEX or 32bit DEC
|
||||||
byte tmpCol[4];
|
|
||||||
pos = req.indexOf(F("CL="));
|
pos = req.indexOf(F("CL="));
|
||||||
if (pos > 0) {
|
if (pos > 0) {
|
||||||
colorFromDecOrHexString(colIn, (char*)req.substring(pos + 3).c_str());
|
colorFromDecOrHexString(colIn, (char*)req.substring(pos + 3).c_str());
|
||||||
@ -991,10 +992,11 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
|||||||
}
|
}
|
||||||
pos = req.indexOf(F("C3="));
|
pos = req.indexOf(F("C3="));
|
||||||
if (pos > 0) {
|
if (pos > 0) {
|
||||||
|
byte tmpCol[4];
|
||||||
colorFromDecOrHexString(tmpCol, (char*)req.substring(pos + 3).c_str());
|
colorFromDecOrHexString(tmpCol, (char*)req.substring(pos + 3).c_str());
|
||||||
uint32_t col2 = RGBW32(tmpCol[0], tmpCol[1], tmpCol[2], tmpCol[3]);
|
col2 = RGBW32(tmpCol[0], tmpCol[1], tmpCol[2], tmpCol[3]);
|
||||||
selseg.setColor(2, col2); // defined above (SS= or main)
|
selseg.setColor(2, col2); // defined above (SS= or main)
|
||||||
if (!singleSegment) strip.setColor(2, col2); // will set color to all active & selected segments
|
col2Changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//set to random hue SR=0->1st SR=1->2nd
|
//set to random hue SR=0->1st SR=1->2nd
|
||||||
@ -1005,29 +1007,22 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
|||||||
col0Changed |= (!sec); col1Changed |= sec;
|
col0Changed |= (!sec); col1Changed |= sec;
|
||||||
}
|
}
|
||||||
|
|
||||||
//swap 2nd & 1st
|
|
||||||
pos = req.indexOf(F("SC"));
|
|
||||||
if (pos > 0) {
|
|
||||||
byte temp;
|
|
||||||
for (unsigned i=0; i<4; i++) {
|
|
||||||
temp = colIn[i];
|
|
||||||
colIn[i] = colInSec[i];
|
|
||||||
colInSec[i] = temp;
|
|
||||||
}
|
|
||||||
col0Changed = col1Changed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// apply colors to selected segment, and all selected segments if applicable
|
// apply colors to selected segment, and all selected segments if applicable
|
||||||
if (col0Changed) {
|
if (col0Changed) {
|
||||||
uint32_t colIn0 = RGBW32(colIn[0], colIn[1], colIn[2], colIn[3]);
|
col0 = RGBW32(colIn[0], colIn[1], colIn[2], colIn[3]);
|
||||||
selseg.setColor(0, colIn0);
|
selseg.setColor(0, col0);
|
||||||
if (!singleSegment) strip.setColor(0, colIn0); // will set color to all active & selected segments
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (col1Changed) {
|
if (col1Changed) {
|
||||||
uint32_t colIn1 = RGBW32(colInSec[0], colInSec[1], colInSec[2], colInSec[3]);
|
col1 = RGBW32(colInSec[0], colInSec[1], colInSec[2], colInSec[3]);
|
||||||
selseg.setColor(1, colIn1);
|
selseg.setColor(1, col1);
|
||||||
if (!singleSegment) strip.setColor(1, colIn1); // will set color to all active & selected segments
|
}
|
||||||
|
|
||||||
|
//swap 2nd & 1st
|
||||||
|
pos = req.indexOf(F("SC"));
|
||||||
|
if (pos > 0) {
|
||||||
|
std::swap(col0,col1);
|
||||||
|
col0Changed = col1Changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool fxModeChanged = false, speedChanged = false, intensityChanged = false, paletteChanged = false;
|
bool fxModeChanged = false, speedChanged = false, intensityChanged = false, paletteChanged = false;
|
||||||
@ -1057,6 +1052,9 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
|||||||
if (speedChanged) seg.speed = speedIn;
|
if (speedChanged) seg.speed = speedIn;
|
||||||
if (intensityChanged) seg.intensity = intensityIn;
|
if (intensityChanged) seg.intensity = intensityIn;
|
||||||
if (paletteChanged) seg.setPalette(paletteIn);
|
if (paletteChanged) seg.setPalette(paletteIn);
|
||||||
|
if (col0Changed) seg.setColor(0, col0);
|
||||||
|
if (col1Changed) seg.setColor(1, col1);
|
||||||
|
if (col2Changed) seg.setColor(2, col2);
|
||||||
if (custom1Changed) seg.custom1 = custom1In;
|
if (custom1Changed) seg.custom1 = custom1In;
|
||||||
if (custom2Changed) seg.custom2 = custom2In;
|
if (custom2Changed) seg.custom2 = custom2In;
|
||||||
if (custom3Changed) seg.custom3 = custom3In;
|
if (custom3Changed) seg.custom3 = custom3In;
|
||||||
|
@ -234,12 +234,12 @@ void parseNotifyPacket(uint8_t *udpIn) {
|
|||||||
//apply colors from notification to main segment, only if not syncing full segments
|
//apply colors from notification to main segment, only if not syncing full segments
|
||||||
if ((receiveNotificationColor || !someSel) && (version < 11 || !receiveSegmentOptions)) {
|
if ((receiveNotificationColor || !someSel) && (version < 11 || !receiveSegmentOptions)) {
|
||||||
// primary color, only apply white if intented (version > 0)
|
// primary color, only apply white if intented (version > 0)
|
||||||
strip.setColor(0, RGBW32(udpIn[3], udpIn[4], udpIn[5], (version > 0) ? udpIn[10] : 0));
|
strip.getMainSegment().setColor(0, RGBW32(udpIn[3], udpIn[4], udpIn[5], (version > 0) ? udpIn[10] : 0));
|
||||||
if (version > 1) {
|
if (version > 1) {
|
||||||
strip.setColor(1, RGBW32(udpIn[12], udpIn[13], udpIn[14], udpIn[15])); // secondary color
|
strip.getMainSegment().setColor(1, RGBW32(udpIn[12], udpIn[13], udpIn[14], udpIn[15])); // secondary color
|
||||||
}
|
}
|
||||||
if (version > 6) {
|
if (version > 6) {
|
||||||
strip.setColor(2, RGBW32(udpIn[20], udpIn[21], udpIn[22], udpIn[23])); // tertiary color
|
strip.getMainSegment().setColor(2, RGBW32(udpIn[20], udpIn[21], udpIn[22], udpIn[23])); // tertiary color
|
||||||
if (version > 9 && udpIn[37] < 255) { // valid CCT/Kelvin value
|
if (version > 9 && udpIn[37] < 255) { // valid CCT/Kelvin value
|
||||||
unsigned cct = udpIn[38];
|
unsigned cct = udpIn[38];
|
||||||
if (udpIn[37] > 0) { //Kelvin
|
if (udpIn[37] > 0) { //Kelvin
|
||||||
@ -260,11 +260,12 @@ void parseNotifyPacket(uint8_t *udpIn) {
|
|||||||
// are we syncing bounds and slave has more active segments than master?
|
// are we syncing bounds and slave has more active segments than master?
|
||||||
if (receiveSegmentBounds && numSrcSegs < strip.getActiveSegmentsNum()) {
|
if (receiveSegmentBounds && numSrcSegs < strip.getActiveSegmentsNum()) {
|
||||||
DEBUG_PRINTLN(F("Removing excessive segments."));
|
DEBUG_PRINTLN(F("Removing excessive segments."));
|
||||||
for (size_t i=strip.getSegmentsNum(); i>numSrcSegs; i--) {
|
strip.suspend(); //should not be needed as UDP handling is not done in ISR callbacks but still added "just in case"
|
||||||
if (strip.getSegment(i).isActive()) {
|
for (size_t i=strip.getSegmentsNum(); i>numSrcSegs && i>0; i--) {
|
||||||
strip.setSegment(i-1,0,0); // delete segment
|
Segment &seg = strip.getSegment(i-1);
|
||||||
}
|
if (seg.isActive()) seg.deactivate(); // delete segment
|
||||||
}
|
}
|
||||||
|
strip.resume();
|
||||||
}
|
}
|
||||||
size_t inactiveSegs = 0;
|
size_t inactiveSegs = 0;
|
||||||
for (size_t i = 0; i < numSrcSegs && i < strip.getMaxSegments(); i++) {
|
for (size_t i = 0; i < numSrcSegs && i < strip.getMaxSegments(); i++) {
|
||||||
@ -300,7 +301,7 @@ void parseNotifyPacket(uint8_t *udpIn) {
|
|||||||
if (!receiveSegmentOptions) {
|
if (!receiveSegmentOptions) {
|
||||||
DEBUG_PRINTF_P(PSTR("Set segment w/o options: %d [%d,%d;%d,%d]\n"), id, (int)start, (int)stop, (int)startY, (int)stopY);
|
DEBUG_PRINTF_P(PSTR("Set segment w/o options: %d [%d,%d;%d,%d]\n"), id, (int)start, (int)stop, (int)startY, (int)stopY);
|
||||||
strip.suspend(); //should not be needed as UDP handling is not done in ISR callbacks but still added "just in case"
|
strip.suspend(); //should not be needed as UDP handling is not done in ISR callbacks but still added "just in case"
|
||||||
selseg.setUp(start, stop, selseg.grouping, selseg.spacing, offset, startY, stopY);
|
selseg.setGeometry(start, stop, selseg.grouping, selseg.spacing, offset, startY, stopY, selseg.map1D2D);
|
||||||
strip.resume();
|
strip.resume();
|
||||||
continue; // we do receive bounds, but not options
|
continue; // we do receive bounds, but not options
|
||||||
}
|
}
|
||||||
@ -342,12 +343,12 @@ void parseNotifyPacket(uint8_t *udpIn) {
|
|||||||
if (receiveSegmentBounds) {
|
if (receiveSegmentBounds) {
|
||||||
DEBUG_PRINTF_P(PSTR("Set segment w/ options: %d [%d,%d;%d,%d]\n"), id, (int)start, (int)stop, (int)startY, (int)stopY);
|
DEBUG_PRINTF_P(PSTR("Set segment w/ options: %d [%d,%d;%d,%d]\n"), id, (int)start, (int)stop, (int)startY, (int)stopY);
|
||||||
strip.suspend(); //should not be needed as UDP handling is not done in ISR callbacks but still added "just in case"
|
strip.suspend(); //should not be needed as UDP handling is not done in ISR callbacks but still added "just in case"
|
||||||
selseg.setUp(start, stop, udpIn[5+ofs], udpIn[6+ofs], offset, startY, stopY);
|
selseg.setGeometry(start, stop, udpIn[5+ofs], udpIn[6+ofs], offset, startY, stopY, selseg.map1D2D);
|
||||||
strip.resume();
|
strip.resume();
|
||||||
} else {
|
} else {
|
||||||
DEBUG_PRINTF_P(PSTR("Set segment grouping: %d [%d,%d]\n"), id, (int)udpIn[5+ofs], (int)udpIn[6+ofs]);
|
DEBUG_PRINTF_P(PSTR("Set segment grouping: %d [%d,%d]\n"), id, (int)udpIn[5+ofs], (int)udpIn[6+ofs]);
|
||||||
strip.suspend(); //should not be needed as UDP handling is not done in ISR callbacks but still added "just in case"
|
strip.suspend(); //should not be needed as UDP handling is not done in ISR callbacks but still added "just in case"
|
||||||
selseg.setUp(selseg.start, selseg.stop, udpIn[5+ofs], udpIn[6+ofs], selseg.offset, selseg.startY, selseg.stopY);
|
selseg.setGeometry(selseg.start, selseg.stop, udpIn[5+ofs], udpIn[6+ofs], selseg.offset, selseg.startY, selseg.stopY, selseg.map1D2D);
|
||||||
strip.resume();
|
strip.resume();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -416,18 +417,18 @@ void realtimeLock(uint32_t timeoutMs, byte md)
|
|||||||
start = mainseg.start;
|
start = mainseg.start;
|
||||||
stop = mainseg.stop;
|
stop = mainseg.stop;
|
||||||
mainseg.freeze = true;
|
mainseg.freeze = true;
|
||||||
|
// if WLED was off and using main segment only, freeze non-main segments so they stay off
|
||||||
|
if (bri == 0) {
|
||||||
|
for (size_t s = 0; s < strip.getSegmentsNum(); s++) {
|
||||||
|
strip.getSegment(s).freeze = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
start = 0;
|
start = 0;
|
||||||
stop = strip.getLengthTotal();
|
stop = strip.getLengthTotal();
|
||||||
}
|
}
|
||||||
// clear strip/segment
|
// clear strip/segment
|
||||||
for (size_t i = start; i < stop; i++) strip.setPixelColor(i,BLACK);
|
for (size_t i = start; i < stop; i++) strip.setPixelColor(i,BLACK);
|
||||||
// if WLED was off and using main segment only, freeze non-main segments so they stay off
|
|
||||||
if (useMainSegmentOnly && bri == 0) {
|
|
||||||
for (size_t s=0; s < strip.getSegmentsNum(); s++) {
|
|
||||||
strip.getSegment(s).freeze = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// if strip is off (bri==0) and not already in RTM
|
// if strip is off (bri==0) and not already in RTM
|
||||||
if (briT == 0 && !realtimeMode && !realtimeOverride) {
|
if (briT == 0 && !realtimeMode && !realtimeOverride) {
|
||||||
@ -510,12 +511,10 @@ void handleNotifications()
|
|||||||
rgbUdp.read(lbuf, packetSize);
|
rgbUdp.read(lbuf, packetSize);
|
||||||
realtimeLock(realtimeTimeoutMs, REALTIME_MODE_HYPERION);
|
realtimeLock(realtimeTimeoutMs, REALTIME_MODE_HYPERION);
|
||||||
if (realtimeOverride && !(realtimeMode && useMainSegmentOnly)) return;
|
if (realtimeOverride && !(realtimeMode && useMainSegmentOnly)) return;
|
||||||
unsigned id = 0;
|
|
||||||
unsigned totalLen = strip.getLengthTotal();
|
unsigned totalLen = strip.getLengthTotal();
|
||||||
for (size_t i = 0; i < packetSize -2; i += 3)
|
if (useMainSegmentOnly) strip.getMainSegment().beginDraw(); // set up parameters for get/setPixelColor()
|
||||||
{
|
for (size_t i = 0, id = 0; i < packetSize -2 && id < totalLen; i += 3, id++) {
|
||||||
setRealtimePixel(id, lbuf[i], lbuf[i+1], lbuf[i+2], 0);
|
setRealtimePixel(id, lbuf[i], lbuf[i+1], lbuf[i+2], 0);
|
||||||
id++; if (id >= totalLen) break;
|
|
||||||
}
|
}
|
||||||
if (!(realtimeMode && useMainSegmentOnly)) strip.show();
|
if (!(realtimeMode && useMainSegmentOnly)) strip.show();
|
||||||
return;
|
return;
|
||||||
@ -595,17 +594,11 @@ void handleNotifications()
|
|||||||
|
|
||||||
unsigned id = (tpmPayloadFrameSize/3)*(packetNum-1); //start LED
|
unsigned id = (tpmPayloadFrameSize/3)*(packetNum-1); //start LED
|
||||||
unsigned totalLen = strip.getLengthTotal();
|
unsigned totalLen = strip.getLengthTotal();
|
||||||
for (size_t i = 6; i < tpmPayloadFrameSize + 4U; i += 3)
|
if (useMainSegmentOnly) strip.getMainSegment().beginDraw(); // set up parameters for get/setPixelColor()
|
||||||
{
|
for (size_t i = 6; i < tpmPayloadFrameSize + 4U && id < totalLen; i += 3, id++) {
|
||||||
if (id < totalLen)
|
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
|
||||||
{
|
|
||||||
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
|
|
||||||
id++;
|
|
||||||
}
|
|
||||||
else break;
|
|
||||||
}
|
}
|
||||||
if (tpmPacketCount == numPackets) //reset packet count and show if all packets were received
|
if (tpmPacketCount == numPackets) { //reset packet count and show if all packets were received
|
||||||
{
|
|
||||||
tpmPacketCount = 0;
|
tpmPacketCount = 0;
|
||||||
strip.show();
|
strip.show();
|
||||||
}
|
}
|
||||||
@ -629,6 +622,7 @@ void handleNotifications()
|
|||||||
if (realtimeOverride && !(realtimeMode && useMainSegmentOnly)) return;
|
if (realtimeOverride && !(realtimeMode && useMainSegmentOnly)) return;
|
||||||
|
|
||||||
unsigned totalLen = strip.getLengthTotal();
|
unsigned totalLen = strip.getLengthTotal();
|
||||||
|
if (useMainSegmentOnly) strip.getMainSegment().beginDraw(); // set up parameters for get/setPixelColor()
|
||||||
if (udpIn[0] == 1 && packetSize > 5) //warls
|
if (udpIn[0] == 1 && packetSize > 5) //warls
|
||||||
{
|
{
|
||||||
for (size_t i = 2; i < packetSize -3; i += 4)
|
for (size_t i = 2; i < packetSize -3; i += 4)
|
||||||
@ -637,39 +631,29 @@ void handleNotifications()
|
|||||||
}
|
}
|
||||||
} else if (udpIn[0] == 2 && packetSize > 4) //drgb
|
} else if (udpIn[0] == 2 && packetSize > 4) //drgb
|
||||||
{
|
{
|
||||||
unsigned id = 0;
|
for (size_t i = 2, id = 0; i < packetSize -2 && id < totalLen; i += 3, id++)
|
||||||
for (size_t i = 2; i < packetSize -2; i += 3)
|
|
||||||
{
|
{
|
||||||
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
|
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
|
||||||
|
|
||||||
id++; if (id >= totalLen) break;
|
|
||||||
}
|
}
|
||||||
} else if (udpIn[0] == 3 && packetSize > 6) //drgbw
|
} else if (udpIn[0] == 3 && packetSize > 6) //drgbw
|
||||||
{
|
{
|
||||||
unsigned id = 0;
|
for (size_t i = 2, id = 0; i < packetSize -3 && id < totalLen; i += 4, id++)
|
||||||
for (size_t i = 2; i < packetSize -3; i += 4)
|
|
||||||
{
|
{
|
||||||
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3]);
|
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3]);
|
||||||
|
|
||||||
id++; if (id >= totalLen) break;
|
|
||||||
}
|
}
|
||||||
} else if (udpIn[0] == 4 && packetSize > 7) //dnrgb
|
} else if (udpIn[0] == 4 && packetSize > 7) //dnrgb
|
||||||
{
|
{
|
||||||
unsigned id = ((udpIn[3] << 0) & 0xFF) + ((udpIn[2] << 8) & 0xFF00);
|
unsigned id = ((udpIn[3] << 0) & 0xFF) + ((udpIn[2] << 8) & 0xFF00);
|
||||||
for (size_t i = 4; i < packetSize -2; i += 3)
|
for (size_t i = 4; i < packetSize -2 && id < totalLen; i += 3, id++)
|
||||||
{
|
{
|
||||||
if (id >= totalLen) break;
|
|
||||||
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
|
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
|
||||||
id++;
|
|
||||||
}
|
}
|
||||||
} else if (udpIn[0] == 5 && packetSize > 8) //dnrgbw
|
} else if (udpIn[0] == 5 && packetSize > 8) //dnrgbw
|
||||||
{
|
{
|
||||||
unsigned id = ((udpIn[3] << 0) & 0xFF) + ((udpIn[2] << 8) & 0xFF00);
|
unsigned id = ((udpIn[3] << 0) & 0xFF) + ((udpIn[2] << 8) & 0xFF00);
|
||||||
for (size_t i = 4; i < packetSize -2; i += 4)
|
for (size_t i = 4; i < packetSize -2 && id < totalLen; i += 4, id++)
|
||||||
{
|
{
|
||||||
if (id >= totalLen) break;
|
|
||||||
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3]);
|
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3]);
|
||||||
id++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
strip.show();
|
strip.show();
|
||||||
@ -704,11 +688,11 @@ void setRealtimePixel(uint16_t i, byte r, byte g, byte b, byte w)
|
|||||||
b = gamma8(b);
|
b = gamma8(b);
|
||||||
w = gamma8(w);
|
w = gamma8(w);
|
||||||
}
|
}
|
||||||
|
uint32_t col = RGBW32(r,g,b,w);
|
||||||
if (useMainSegmentOnly) {
|
if (useMainSegmentOnly) {
|
||||||
Segment &seg = strip.getMainSegment();
|
strip.getMainSegment().setPixelColor(pix, col); // this expects that strip.getMainSegment().beginDraw() has been called in handleNotification()
|
||||||
if (pix<seg.length()) seg.setPixelColor(pix, r, g, b, w);
|
|
||||||
} else {
|
} else {
|
||||||
strip.setPixelColor(pix, r, g, b, w);
|
strip.setPixelColor(pix, col);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USERMOD_BH1750
|
#ifdef USERMOD_BH1750
|
||||||
#include "../usermods/BH1750_v2/usermod_BH1750.h"
|
#include "../usermods/BH1750_v2/usermod_bh1750.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// BME280 v2 usermod. Define "USERMOD_BME280" in my_config.h
|
// BME280 v2 usermod. Define "USERMOD_BME280" in my_config.h
|
||||||
|
@ -14,7 +14,7 @@ int getNumVal(const String* req, uint16_t pos)
|
|||||||
void parseNumber(const char* str, byte* val, byte minv, byte maxv)
|
void parseNumber(const char* str, byte* val, byte minv, byte maxv)
|
||||||
{
|
{
|
||||||
if (str == nullptr || str[0] == '\0') return;
|
if (str == nullptr || str[0] == '\0') return;
|
||||||
if (str[0] == 'r') {*val = random8(minv,maxv?maxv:255); return;} // maxv for random cannot be 0
|
if (str[0] == 'r') {*val = hw_random8(minv,maxv?maxv:255); return;} // maxv for random cannot be 0
|
||||||
bool wrap = false;
|
bool wrap = false;
|
||||||
if (str[0] == 'w' && strlen(str) > 1) {str++; wrap = true;}
|
if (str[0] == 'w' && strlen(str) > 1) {str++; wrap = true;}
|
||||||
if (str[0] == '~') {
|
if (str[0] == '~') {
|
||||||
@ -474,9 +474,9 @@ um_data_t* simulateSound(uint8_t simulationId)
|
|||||||
break;
|
break;
|
||||||
case UMS_WeWillRockYou:
|
case UMS_WeWillRockYou:
|
||||||
if (ms%2000 < 200) {
|
if (ms%2000 < 200) {
|
||||||
volumeSmth = random8(255);
|
volumeSmth = hw_random8();
|
||||||
for (int i = 0; i<5; i++)
|
for (int i = 0; i<5; i++)
|
||||||
fftResult[i] = random8(255);
|
fftResult[i] = hw_random8();
|
||||||
}
|
}
|
||||||
else if (ms%2000 < 400) {
|
else if (ms%2000 < 400) {
|
||||||
volumeSmth = 0;
|
volumeSmth = 0;
|
||||||
@ -484,9 +484,9 @@ um_data_t* simulateSound(uint8_t simulationId)
|
|||||||
fftResult[i] = 0;
|
fftResult[i] = 0;
|
||||||
}
|
}
|
||||||
else if (ms%2000 < 600) {
|
else if (ms%2000 < 600) {
|
||||||
volumeSmth = random8(255);
|
volumeSmth = hw_random8();
|
||||||
for (int i = 5; i<11; i++)
|
for (int i = 5; i<11; i++)
|
||||||
fftResult[i] = random8(255);
|
fftResult[i] = hw_random8();
|
||||||
}
|
}
|
||||||
else if (ms%2000 < 800) {
|
else if (ms%2000 < 800) {
|
||||||
volumeSmth = 0;
|
volumeSmth = 0;
|
||||||
@ -494,9 +494,9 @@ um_data_t* simulateSound(uint8_t simulationId)
|
|||||||
fftResult[i] = 0;
|
fftResult[i] = 0;
|
||||||
}
|
}
|
||||||
else if (ms%2000 < 1000) {
|
else if (ms%2000 < 1000) {
|
||||||
volumeSmth = random8(255);
|
volumeSmth = hw_random8();
|
||||||
for (int i = 11; i<16; i++)
|
for (int i = 11; i<16; i++)
|
||||||
fftResult[i] = random8(255);
|
fftResult[i] = hw_random8();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
volumeSmth = 0;
|
volumeSmth = 0;
|
||||||
@ -516,7 +516,7 @@ um_data_t* simulateSound(uint8_t simulationId)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
samplePeak = random8() > 250;
|
samplePeak = hw_random8() > 250;
|
||||||
FFT_MajorPeak = 21 + (volumeSmth*volumeSmth) / 8.0f; // walk thru full range of 21hz...8200hz
|
FFT_MajorPeak = 21 + (volumeSmth*volumeSmth) / 8.0f; // walk thru full range of 21hz...8200hz
|
||||||
maxVol = 31; // this gets feedback fro UI
|
maxVol = 31; // this gets feedback fro UI
|
||||||
binNum = 8; // this gets feedback fro UI
|
binNum = 8; // this gets feedback fro UI
|
||||||
@ -582,7 +582,7 @@ void enumerateLedmaps() {
|
|||||||
uint8_t get_random_wheel_index(uint8_t pos) {
|
uint8_t get_random_wheel_index(uint8_t pos) {
|
||||||
uint8_t r = 0, x = 0, y = 0, d = 0;
|
uint8_t r = 0, x = 0, y = 0, d = 0;
|
||||||
while (d < 42) {
|
while (d < 42) {
|
||||||
r = random8();
|
r = hw_random8();
|
||||||
x = abs(pos - r);
|
x = abs(pos - r);
|
||||||
y = 255 - x;
|
y = 255 - x;
|
||||||
d = MIN(x, y);
|
d = MIN(x, y);
|
||||||
@ -594,3 +594,18 @@ uint8_t get_random_wheel_index(uint8_t pos) {
|
|||||||
float mapf(float x, float in_min, float in_max, float out_min, float out_max) {
|
float mapf(float x, float in_min, float in_max, float out_min, float out_max) {
|
||||||
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
|
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 32 bit random number generator, inlining uses more code, use hw_random16() if speed is critical (see fcn_declare.h)
|
||||||
|
uint32_t hw_random(uint32_t upperlimit) {
|
||||||
|
uint32_t rnd = hw_random();
|
||||||
|
uint64_t scaled = uint64_t(rnd) * uint64_t(upperlimit);
|
||||||
|
return scaled >> 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t hw_random(int32_t lowerlimit, int32_t upperlimit) {
|
||||||
|
if(lowerlimit >= upperlimit) {
|
||||||
|
return lowerlimit;
|
||||||
|
}
|
||||||
|
uint32_t diff = upperlimit - lowerlimit;
|
||||||
|
return hw_random(diff) + lowerlimit;
|
||||||
|
}
|
@ -222,6 +222,7 @@ void WLED::loop()
|
|||||||
BusManager::setBrightness(bri); // fix re-initialised bus' brightness #4005
|
BusManager::setBrightness(bri); // fix re-initialised bus' brightness #4005
|
||||||
if (aligned) strip.makeAutoSegments();
|
if (aligned) strip.makeAutoSegments();
|
||||||
else strip.fixInvalidSegments();
|
else strip.fixInvalidSegments();
|
||||||
|
BusManager::setBrightness(bri); // fix re-initialised bus' brightness
|
||||||
doSerializeConfig = true;
|
doSerializeConfig = true;
|
||||||
}
|
}
|
||||||
if (loadLedmap >= 0) {
|
if (loadLedmap >= 0) {
|
||||||
@ -543,14 +544,8 @@ void WLED::setup()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Seed FastLED random functions with an esp random value, which already works properly at this point.
|
// Seed FastLED random functions with an esp random value, which already works properly at this point.
|
||||||
#if defined(ARDUINO_ARCH_ESP32)
|
const uint32_t seed32 = hw_random();
|
||||||
const uint32_t seed32 = esp_random();
|
random16_set_seed((uint16_t)seed32);
|
||||||
#elif defined(ARDUINO_ARCH_ESP8266)
|
|
||||||
const uint32_t seed32 = RANDOM_REG32;
|
|
||||||
#else
|
|
||||||
const uint32_t seed32 = random(std::numeric_limits<long>::max());
|
|
||||||
#endif
|
|
||||||
random16_set_seed((uint16_t)((seed32 & 0xFFFF) ^ (seed32 >> 16)));
|
|
||||||
|
|
||||||
#if WLED_WATCHDOG_TIMEOUT > 0
|
#if WLED_WATCHDOG_TIMEOUT > 0
|
||||||
enableWatchdog();
|
enableWatchdog();
|
||||||
@ -575,10 +570,11 @@ void WLED::beginStrip()
|
|||||||
} else {
|
} else {
|
||||||
// fix for #3196
|
// fix for #3196
|
||||||
if (bootPreset > 0) {
|
if (bootPreset > 0) {
|
||||||
bool oldTransition = fadeTransition; // workaround if transitions are enabled
|
// set all segments black (no transition)
|
||||||
fadeTransition = false; // ignore transitions temporarily
|
for (unsigned i = 0; i < strip.getSegmentsNum(); i++) {
|
||||||
strip.setColor(0, BLACK); // set all segments black
|
Segment &seg = strip.getSegment(i);
|
||||||
fadeTransition = oldTransition; // restore transitions
|
if (seg.isActive()) seg.colors[0] = BLACK;
|
||||||
|
}
|
||||||
col[0] = col[1] = col[2] = col[3] = 0; // needed for colorUpdated()
|
col[0] = col[1] = col[2] = col[3] = 0; // needed for colorUpdated()
|
||||||
}
|
}
|
||||||
briLast = briS; bri = 0;
|
briLast = briS; bri = 0;
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
/*
|
/*
|
||||||
Main sketch, global variable declarations
|
Main sketch, global variable declarations
|
||||||
@title WLED project sketch
|
@title WLED project sketch
|
||||||
@version 0.15.0-dev
|
|
||||||
@author Christian Schwinne
|
@author Christian Schwinne
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -583,7 +582,6 @@ WLED_GLOBAL bool transitionActive _INIT(false);
|
|||||||
WLED_GLOBAL uint16_t transitionDelay _INIT(750); // global transition duration
|
WLED_GLOBAL uint16_t transitionDelay _INIT(750); // global transition duration
|
||||||
WLED_GLOBAL uint16_t transitionDelayDefault _INIT(750); // default transition time (stored in cfg.json)
|
WLED_GLOBAL uint16_t transitionDelayDefault _INIT(750); // default transition time (stored in cfg.json)
|
||||||
WLED_GLOBAL unsigned long transitionStartTime;
|
WLED_GLOBAL unsigned long transitionStartTime;
|
||||||
WLED_GLOBAL float tperLast _INIT(0.0f); // crossfade transition progress, 0.0f - 1.0f
|
|
||||||
WLED_GLOBAL bool jsonTransitionOnce _INIT(false); // flag to override transitionDelay (playlist, JSON API: "live" & "seg":{"i"} & "tt")
|
WLED_GLOBAL bool jsonTransitionOnce _INIT(false); // flag to override transitionDelay (playlist, JSON API: "live" & "seg":{"i"} & "tt")
|
||||||
WLED_GLOBAL uint8_t randomPaletteChangeTime _INIT(5); // amount of time [s] between random palette changes (min: 1s, max: 255s)
|
WLED_GLOBAL uint8_t randomPaletteChangeTime _INIT(5); // amount of time [s] between random palette changes (min: 1s, max: 255s)
|
||||||
WLED_GLOBAL bool useHarmonicRandomPalette _INIT(true); // use *harmonic* random palette generation (nicer looking) or truly random
|
WLED_GLOBAL bool useHarmonicRandomPalette _INIT(true); // use *harmonic* random palette generation (nicer looking) or truly random
|
||||||
|
Loading…
x
Reference in New Issue
Block a user