2D Game of Life update.
Added crc16(). Reduced errorToast popup time. Fixed drawLine() incorrect uint16_t use and added leds[] support.
This commit is contained in:
parent
d8be286831
commit
ba3555a66f
164
wled00/FX.cpp
164
wled00/FX.cpp
@ -4311,10 +4311,11 @@ uint16_t WS2812FX::mode_2DBlackHole(void) { // By: Stepko https://edi
|
|||||||
// blur everything a bit
|
// blur everything a bit
|
||||||
blur2d(leds, 16);
|
blur2d(leds, 16);
|
||||||
|
|
||||||
for (y = 0; y < h; y++) for (x = 0; x < w; x++) {
|
// for (y = 0; y < h; y++) for (x = 0; x < w; x++) {
|
||||||
uint16_t o = x + y * w;
|
// uint16_t o = x + y * w;
|
||||||
setPixelColorXY(x, y, leds[o]);
|
// setPixelColorXY(x, y, leds[o]);
|
||||||
}
|
// }
|
||||||
|
setPixels(leds);
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
} // mode_2DBlackHole()
|
} // mode_2DBlackHole()
|
||||||
|
|
||||||
@ -4551,114 +4552,95 @@ typedef struct ColorCount {
|
|||||||
int8_t count;
|
int8_t count;
|
||||||
} colorCount;
|
} colorCount;
|
||||||
|
|
||||||
|
static unsigned long resetMillis; //triggers reset if more than 3 seconds from now
|
||||||
uint16_t WS2812FX::mode_2Dgameoflife(void) { // Written by Ewoud Wijma, inspired by https://natureofcode.com/book/chapter-7-cellular-automata/ and https://github.com/DougHaber/nlife-color
|
uint16_t WS2812FX::mode_2Dgameoflife(void) { // Written by Ewoud Wijma, inspired by https://natureofcode.com/book/chapter-7-cellular-automata/ and https://github.com/DougHaber/nlife-color
|
||||||
if (!isMatrix) return mode_static(); // not a 2D set-up
|
if (!isMatrix) return mode_static(); // not a 2D set-up
|
||||||
|
|
||||||
uint16_t width = SEGMENT.virtualWidth();
|
const uint16_t width = SEGMENT.virtualWidth();
|
||||||
uint16_t height = SEGMENT.virtualHeight();
|
const uint16_t height = SEGMENT.virtualHeight();
|
||||||
uint16_t dataSize = sizeof(CRGB) * width * height;
|
const uint16_t dataSize = sizeof(CRGB) * width * height;
|
||||||
|
|
||||||
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
|
if (!SEGENV.allocateData(dataSize*2)) return mode_static(); //allocation failed
|
||||||
CRGB *leds = reinterpret_cast<CRGB*>(SEGENV.data);
|
CRGB *leds = reinterpret_cast<CRGB*>(SEGENV.data);
|
||||||
|
CRGB *prevLeds = reinterpret_cast<CRGB*>(SEGENV.data) + dataSize;
|
||||||
|
|
||||||
if (SEGENV.call == 0) fill_solid(leds, CRGB::Black);
|
CRGB backgroundColor = SEGCOLOR(1);
|
||||||
|
|
||||||
//slow down based on speed parameter
|
if (SEGENV.call == 0 || now - resetMillis > 20000) {
|
||||||
if (now - SEGENV.step >= ((255-SEGMENT.speed)*4U)) {
|
resetMillis = now;
|
||||||
SEGENV.step = now;
|
|
||||||
|
|
||||||
//array of patterns. Needed to identify repeating patterns. A pattern is one iteration of leds, without the color (on/off only)
|
random16_set_seed(now); //seed the random generator
|
||||||
const int patternsSize = (width + height) * 2; //seems to be a good value to catch also repetition in moving patterns
|
|
||||||
unsigned long long patterns[patternsSize];
|
|
||||||
|
|
||||||
CRGB backgroundColor = SEGCOLOR(1);
|
//give the leds random state and colors (based on intensity, colors from palette or all posible colors are chosen)
|
||||||
|
for (int x = 0; x < width; x++) for (int y = 0; y < height; y++) {
|
||||||
static unsigned long resetMillis = now - 3000; //triggers reset if more than 3 seconds from now
|
uint8_t state = random8()%2;
|
||||||
|
if (state == 0)
|
||||||
if (SEGENV.call == 0) { //effect starts
|
leds[XY(x,y)] = backgroundColor;
|
||||||
for (int i=0; i<patternsSize; i++) patterns[i] = 0;
|
else
|
||||||
|
leds[XY(x,y)] = (CRGB)color_from_palette(random8(), false, PALETTE_SOLID_WRAP, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
//reset leds if effect repeats (wait 3 seconds after repetition)
|
fill_solid(prevLeds, CRGB::Black);
|
||||||
if (now - resetMillis > 3000) {
|
|
||||||
resetMillis = now;
|
|
||||||
|
|
||||||
random16_set_seed(now); //seed the random generator
|
SEGENV.aux1 = 0;
|
||||||
|
SEGENV.aux0 = 0xFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
//give the leds random state and colors (based on intensity, colors from palette or all posible colors are chosen)
|
//copy previous leds (save previous generation)
|
||||||
for (int x = 0; x < width; x++) for (int y = 0; y < height; y++) {
|
for (int x = 0; x < width; x++) for (int y = 0; y < height; y++) prevLeds[XY(x,y)] = leds[XY(x,y)];
|
||||||
uint8_t state = random8()%2;
|
|
||||||
if (state == 0)
|
|
||||||
leds[XY(x,y)] = backgroundColor;
|
|
||||||
else
|
|
||||||
leds[XY(x,y)] = SEGMENT.intensity < 128?(CRGB)color_wheel(random8()):CRGB(random8(), random8(), random8());
|
|
||||||
}
|
|
||||||
|
|
||||||
//init patterns
|
//calculate new leds
|
||||||
SEGENV.aux0 = 0; //ewowi20210629: pka static! patternsize: round robin index of next slot to add pattern
|
for (int x = 0; x < width; x++) for (int y = 0; y < height; y++) {
|
||||||
for (int i=0; i<patternsSize; i++) patterns[i] = 0;
|
colorCount colorsCount[9];//count the different colors in the 9*9 matrix
|
||||||
|
for (int i=0; i<9; i++) colorsCount[i] = {backgroundColor, 0}; //init colorsCount
|
||||||
|
|
||||||
} else {
|
//iterate through neighbors and count them and their different colors
|
||||||
|
int neighbors = 0;
|
||||||
|
for (int i = -1; i <= 1; i++) for (int j = -1; j <= 1; j++) { //iterate through 9*9 matrix
|
||||||
|
// wrap around segment
|
||||||
|
int16_t xx = x+i, yy = y+j;
|
||||||
|
if (x+i < 0) xx = width-1; else if (x+i >= width) xx = 0;
|
||||||
|
if (y+j < 0) yy = height-1; else if (y+j >= height) yy = 0;
|
||||||
|
uint16_t xy = XY(xx, yy); // previous cell xy to check
|
||||||
|
|
||||||
//calculate new leds
|
// count different neighbours and colors, except the centre cell
|
||||||
for (int x = 1; x < width-1; x++) for (int y = 1; y < height-1; y++) {
|
if (xy != XY(x,y) && prevLeds[xy] != backgroundColor) {
|
||||||
colorCount colorsCount[9];//count the different colors in the 9*9 matrix
|
neighbors++;
|
||||||
for (int i=0; i<9; i++) colorsCount[i] = {backgroundColor, 0}; //init colorsCount
|
bool colorFound = false;
|
||||||
|
int k;
|
||||||
//iterate through neighbors and count them and their different colors
|
for (k=0; k<9 && colorsCount[i].count != 0; k++)
|
||||||
int neighbors = 0;
|
if (colorsCount[k].color == prevLeds[xy]) {
|
||||||
for (int i = -1; i <= 1; i++) for (int j = -1; j <= 1; j++) { //iterate through 9*9 matrix
|
colorsCount[k].count++;
|
||||||
uint16_t xy = XY(x+i, y+j); //cell xy to check
|
colorFound = true;
|
||||||
|
|
||||||
// count different neighbours and colors, except the centre cell
|
|
||||||
if (xy != XY(x,y) && leds[xy] != backgroundColor) {
|
|
||||||
neighbors++;
|
|
||||||
bool colorFound = false;
|
|
||||||
int i;
|
|
||||||
for (i=0; i<9 && colorsCount[i].count != 0; i++)
|
|
||||||
if (colorsCount[i].color == leds[xy]) {
|
|
||||||
colorsCount[i].count++;
|
|
||||||
colorFound = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!colorFound) colorsCount[i] = {leds[xy], 1}; //add new color found in the array
|
|
||||||
}
|
}
|
||||||
} // i,j
|
|
||||||
|
|
||||||
// Rules of Life
|
if (!colorFound) colorsCount[k] = {prevLeds[xy], 1}; //add new color found in the array
|
||||||
if ((leds[XY(x,y)] != backgroundColor) && (neighbors < 2)) leds[XY(x,y)] = backgroundColor; // Loneliness
|
}
|
||||||
else if ((leds[XY(x,y)] != backgroundColor) && (neighbors > 3)) leds[XY(x,y)] = backgroundColor; // Overpopulation
|
} // i,j
|
||||||
else if ((leds[XY(x,y)] == backgroundColor) && (neighbors == 3)) { // Reproduction
|
|
||||||
//find dominantcolor and assign to cell
|
|
||||||
colorCount dominantColorCount = {backgroundColor, 0};
|
|
||||||
for (int i=0; i<9 && colorsCount[i].count != 0; i++)
|
|
||||||
if (colorsCount[i].count > dominantColorCount.count) dominantColorCount = colorsCount[i];
|
|
||||||
if (dominantColorCount.count > 0) leds[XY(x,y)] = dominantColorCount.color; //assign the dominant color
|
|
||||||
}
|
|
||||||
// else do nothing!
|
|
||||||
} //x,y
|
|
||||||
|
|
||||||
//create new pattern
|
// Rules of Life
|
||||||
unsigned long long pattern = 0;
|
if ((leds[XY(x,y)] != backgroundColor) && (neighbors < 2)) leds[XY(x,y)] = backgroundColor; // Loneliness
|
||||||
for (int x = 0; x < width; x+=MAX(width/8,1)) for (int y = 0; y < height; y+=MAX(height/8,1))
|
else if ((leds[XY(x,y)] != backgroundColor) && (neighbors > 3)) leds[XY(x,y)] = backgroundColor; // Overpopulation
|
||||||
pattern = (pattern<<1) | !(leds[XY(x,y)] == backgroundColor);
|
else if ((leds[XY(x,y)] == backgroundColor) && (neighbors == 3)) { // Reproduction
|
||||||
|
//find dominantcolor and assign to cell
|
||||||
|
colorCount dominantColorCount = {backgroundColor, 0};
|
||||||
|
for (int i=0; i<9 && colorsCount[i].count != 0; i++)
|
||||||
|
if (colorsCount[i].count > dominantColorCount.count) dominantColorCount = colorsCount[i];
|
||||||
|
if (dominantColorCount.count > 0) leds[XY(x,y)] = dominantColorCount.color; //assign the dominant color
|
||||||
|
}
|
||||||
|
// else do nothing!
|
||||||
|
} //x,y
|
||||||
|
|
||||||
//check if repetition of patterns occurs
|
// calculate CRC16 of leds[]
|
||||||
bool repetition = false;
|
uint16_t crc = crc16((const unsigned char*)leds, dataSize);
|
||||||
for (int i=0; i<patternsSize && !repetition; i++)
|
// check if we had same CRC and reset if needed
|
||||||
repetition = patterns[(SEGENV.aux0 - 1 - i + patternsSize)%patternsSize] == pattern;
|
if (!(crc == SEGENV.aux0 || crc == SEGENV.aux1)) resetMillis = now; //if no repetition avoid reset
|
||||||
|
// remeber last two
|
||||||
|
SEGENV.aux1 = SEGENV.aux0;
|
||||||
|
SEGENV.aux0 = crc;
|
||||||
|
|
||||||
//add current pattern to array and increase index (round robin)
|
setPixels(leds);
|
||||||
patterns[SEGENV.aux0] = pattern;
|
return FRAMETIME_FIXED * (128-(SEGMENT.speed>>1)); // update only when appropriate time passes (in 42 FPS slots)
|
||||||
SEGENV.aux0 = (++SEGENV.aux0)%patternsSize;
|
|
||||||
|
|
||||||
if (!repetition) resetMillis = now; //if no repetition avoid reset
|
|
||||||
} //not reset
|
|
||||||
|
|
||||||
setPixels(leds);
|
|
||||||
} //millis
|
|
||||||
|
|
||||||
return FRAMETIME;
|
|
||||||
} // mode_2Dgameoflife()
|
} // mode_2Dgameoflife()
|
||||||
|
|
||||||
/////////////////////////
|
/////////////////////////
|
||||||
|
@ -920,10 +920,11 @@ class WS2812FX {
|
|||||||
fadeToBlackBy(CRGB* leds, uint8_t fadeBy),
|
fadeToBlackBy(CRGB* leds, uint8_t fadeBy),
|
||||||
nscale8(CRGB* leds, uint8_t scale),
|
nscale8(CRGB* leds, uint8_t scale),
|
||||||
setPixels(CRGB* leds),
|
setPixels(CRGB* leds),
|
||||||
drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1,CRGB c);
|
drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, CRGB c, CRGB *leds = nullptr);
|
||||||
|
|
||||||
inline void setPixelColorXY(uint16_t x, uint16_t y, uint32_t c) { setPixelColorXY(x, y, byte(c>>16), byte(c>>8), byte(c), byte(c>>24)); }
|
inline void setPixelColorXY(uint16_t x, uint16_t y, uint32_t c) { setPixelColorXY(x, y, byte(c>>16), byte(c>>8), byte(c), byte(c>>24)); }
|
||||||
inline void setPixelColorXY(uint16_t x, uint16_t y, CRGB &c) { setPixelColorXY(x, y, c.red, c.green, c.blue); }
|
inline void setPixelColorXY(uint16_t x, uint16_t y, CRGB c) { setPixelColorXY(x, y, c.red, c.green, c.blue); }
|
||||||
|
inline void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c) { drawLine(x0, y0, x1, y1, CRGB(byte(c>>16), byte(c>>8), byte(c))); }
|
||||||
|
|
||||||
uint16_t
|
uint16_t
|
||||||
XY(uint16_t, uint16_t),
|
XY(uint16_t, uint16_t),
|
||||||
|
@ -334,13 +334,13 @@ void WS2812FX::setPixels(CRGB* leds) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//line function
|
//line function
|
||||||
void WS2812FX::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1,CRGB c) {
|
void WS2812FX::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, CRGB c, CRGB *leds) {
|
||||||
|
int16_t dx = abs(x1-x0), sx = x0<x1 ? 1 : -1;
|
||||||
uint16_t dx = abs(x1-x0), sx = x0<x1 ? 1 : -1;
|
int16_t dy = abs(y1-y0), sy = y0<y1 ? 1 : -1;
|
||||||
uint16_t dy = abs(y1-y0), sy = y0<y1 ? 1 : -1;
|
int16_t err = (dx>dy ? dx : -dy)/2, e2;
|
||||||
uint16_t err = (dx>dy ? dx : -dy)/2, e2;
|
for (;;) {
|
||||||
for(;;){
|
if (leds == nullptr) setPixelColorXY(x0,y0,c);
|
||||||
setPixelColorXY(x0,y0,c);
|
else leds[XY(x0,y0)] = c;
|
||||||
if (x0==x1 && y0==y1) break;
|
if (x0==x1 && y0==y1) break;
|
||||||
e2 = err;
|
e2 = err;
|
||||||
if (e2 >-dx) { err -= dy; x0 += sx; }
|
if (e2 >-dx) { err -= dy; x0 += sx; }
|
||||||
|
@ -1443,7 +1443,7 @@ const char JSON_mode_names[] PROGMEM = R"=====([
|
|||||||
"2D Matrix@Falling speed,Spawning rate,Trail,Custom color;Spawn,Trail;",
|
"2D Matrix@Falling speed,Spawning rate,Trail,Custom color;Spawn,Trail;",
|
||||||
"2D Akemi@Color speed,Dance;Head palette,Arms & Legs,Eyes & Mouth;Face palette",
|
"2D Akemi@Color speed,Dance;Head palette,Arms & Legs,Eyes & Mouth;Face palette",
|
||||||
"2D Colored Bursts@Speed,Number of lines;;!",
|
"2D Colored Bursts@Speed,Number of lines;;!",
|
||||||
"2D Game Of Life@!,Palette;!,!;!",
|
"2D Game Of Life@!,;!,!;!",
|
||||||
"2D Julia@,Max iterations per pixel,X center,Y center,Area size;;!",
|
"2D Julia@,Max iterations per pixel,X center,Y center,Area size;;!",
|
||||||
"2D Metaballs@Speed;!,!,!;!",
|
"2D Metaballs@Speed;!,!,!;!",
|
||||||
"2D Noise@Speed,Scale;!,!,!;!",
|
"2D Noise@Speed,Scale;!,!,!;!",
|
||||||
|
@ -304,7 +304,7 @@ function showErrorToast()
|
|||||||
showToast('Connection to light failed!', true);
|
showToast('Connection to light failed!', true);
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearErrorToast(n=10000)
|
function clearErrorToast(n=5000)
|
||||||
{
|
{
|
||||||
var x = gId("toast");
|
var x = gId("toast");
|
||||||
if (x.classList.contains("error")) {
|
if (x.classList.contains("error")) {
|
||||||
@ -943,7 +943,7 @@ function loadNodes()
|
|||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.then((json)=>{
|
.then((json)=>{
|
||||||
clearErrorToast();
|
clearErrorToast(100);
|
||||||
populateNodes(lastinfo, json);
|
populateNodes(lastinfo, json);
|
||||||
})
|
})
|
||||||
.catch((e)=>{
|
.catch((e)=>{
|
||||||
@ -1429,7 +1429,7 @@ function requestJson(command=null)
|
|||||||
})
|
})
|
||||||
.then(json => {
|
.then(json => {
|
||||||
lastUpdate = new Date();
|
lastUpdate = new Date();
|
||||||
clearErrorToast();
|
clearErrorToast(3000);
|
||||||
gId('connind').style.backgroundColor = "var(--c-g)";
|
gId('connind').style.backgroundColor = "var(--c-g)";
|
||||||
if (!json) { showToast('Empty response', true); return; }
|
if (!json) { showToast('Empty response', true); return; }
|
||||||
if (json.success) return;
|
if (json.success) return;
|
||||||
|
@ -278,6 +278,7 @@ bool isAsterisksOnly(const char* str, byte maxLen);
|
|||||||
bool requestJSONBufferLock(uint8_t module=255);
|
bool requestJSONBufferLock(uint8_t module=255);
|
||||||
void releaseJSONBufferLock();
|
void releaseJSONBufferLock();
|
||||||
uint8_t extractModeName(uint8_t mode, const char *src, char *dest, uint8_t maxLen);
|
uint8_t extractModeName(uint8_t mode, const char *src, char *dest, uint8_t maxLen);
|
||||||
|
uint16_t crc16(const unsigned char* data_p, size_t length);
|
||||||
|
|
||||||
//wled_eeprom.cpp
|
//wled_eeprom.cpp
|
||||||
void applyMacro(byte index);
|
void applyMacro(byte index);
|
||||||
|
3485
wled00/html_ui.h
3485
wled00/html_ui.h
File diff suppressed because it is too large
Load Diff
@ -260,3 +260,15 @@ uint8_t extractModeName(uint8_t mode, const char *src, char *dest, uint8_t maxLe
|
|||||||
dest[printedChars] = '\0';
|
dest[printedChars] = '\0';
|
||||||
return strlen(dest);
|
return strlen(dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint16_t crc16(const unsigned char* data_p, size_t length) {
|
||||||
|
uint8_t x;
|
||||||
|
uint16_t crc = 0xFFFF;
|
||||||
|
if (!length) return 0x1D0F;
|
||||||
|
while (length--) {
|
||||||
|
x = crc >> 8 ^ *data_p++;
|
||||||
|
x ^= x>>4;
|
||||||
|
crc = (crc << 8) ^ ((uint16_t)(x << 12)) ^ ((uint16_t)(x <<5)) ^ ((uint16_t)x);
|
||||||
|
}
|
||||||
|
return crc;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user