2D Game of Life update.

Added crc16().
Reduced errorToast popup time.
Fixed drawLine() incorrect uint16_t use and added leds[] support.
pull/2737/head
Blaz Kristan 2022-05-20 14:48:40 +02:00
rodzic d8be286831
commit ba3555a66f
8 zmienionych plików z 1843 dodań i 1846 usunięć

Wyświetl plik

@ -4311,10 +4311,11 @@ uint16_t WS2812FX::mode_2DBlackHole(void) { // By: Stepko https://edi
// blur everything a bit
blur2d(leds, 16);
for (y = 0; y < h; y++) for (x = 0; x < w; x++) {
uint16_t o = x + y * w;
setPixelColorXY(x, y, leds[o]);
}
// for (y = 0; y < h; y++) for (x = 0; x < w; x++) {
// uint16_t o = x + y * w;
// setPixelColorXY(x, y, leds[o]);
// }
setPixels(leds);
return FRAMETIME;
} // mode_2DBlackHole()
@ -4551,114 +4552,95 @@ typedef struct ColorCount {
int8_t count;
} 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
if (!isMatrix) return mode_static(); // not a 2D set-up
uint16_t width = SEGMENT.virtualWidth();
uint16_t height = SEGMENT.virtualHeight();
uint16_t dataSize = sizeof(CRGB) * width * height;
const uint16_t width = SEGMENT.virtualWidth();
const uint16_t height = SEGMENT.virtualHeight();
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 *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 (now - SEGENV.step >= ((255-SEGMENT.speed)*4U)) {
SEGENV.step = now;
if (SEGENV.call == 0 || now - resetMillis > 20000) {
resetMillis = now;
//array of patterns. Needed to identify repeating patterns. A pattern is one iteration of leds, without the color (on/off only)
const int patternsSize = (width + height) * 2; //seems to be a good value to catch also repetition in moving patterns
unsigned long long patterns[patternsSize];
random16_set_seed(now); //seed the random generator
CRGB backgroundColor = SEGCOLOR(1);
static unsigned long resetMillis = now - 3000; //triggers reset if more than 3 seconds from now
if (SEGENV.call == 0) { //effect starts
for (int i=0; i<patternsSize; i++) patterns[i] = 0;
//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++) {
uint8_t state = random8()%2;
if (state == 0)
leds[XY(x,y)] = backgroundColor;
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)
if (now - resetMillis > 3000) {
resetMillis = now;
fill_solid(prevLeds, CRGB::Black);
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)
for (int x = 0; x < width; x++) for (int y = 0; y < height; 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());
}
//copy previous leds (save previous generation)
for (int x = 0; x < width; x++) for (int y = 0; y < height; y++) prevLeds[XY(x,y)] = leds[XY(x,y)];
//init patterns
SEGENV.aux0 = 0; //ewowi20210629: pka static! patternsize: round robin index of next slot to add pattern
for (int i=0; i<patternsSize; i++) patterns[i] = 0;
//calculate new leds
for (int x = 0; x < width; x++) for (int y = 0; y < height; y++) {
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
for (int x = 1; x < width-1; x++) for (int y = 1; y < height-1; y++) {
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
//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
uint16_t xy = XY(x+i, y+j); //cell xy to check
// 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
// count different neighbours and colors, except the centre cell
if (xy != XY(x,y) && prevLeds[xy] != backgroundColor) {
neighbors++;
bool colorFound = false;
int k;
for (k=0; k<9 && colorsCount[i].count != 0; k++)
if (colorsCount[k].color == prevLeds[xy]) {
colorsCount[k].count++;
colorFound = true;
}
} // i,j
// Rules of Life
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
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
if (!colorFound) colorsCount[k] = {prevLeds[xy], 1}; //add new color found in the array
}
} // i,j
//create new pattern
unsigned long long pattern = 0;
for (int x = 0; x < width; x+=MAX(width/8,1)) for (int y = 0; y < height; y+=MAX(height/8,1))
pattern = (pattern<<1) | !(leds[XY(x,y)] == backgroundColor);
// Rules of Life
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
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
bool repetition = false;
for (int i=0; i<patternsSize && !repetition; i++)
repetition = patterns[(SEGENV.aux0 - 1 - i + patternsSize)%patternsSize] == pattern;
// calculate CRC16 of leds[]
uint16_t crc = crc16((const unsigned char*)leds, dataSize);
// check if we had same CRC and reset if needed
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)
patterns[SEGENV.aux0] = pattern;
SEGENV.aux0 = (++SEGENV.aux0)%patternsSize;
if (!repetition) resetMillis = now; //if no repetition avoid reset
} //not reset
setPixels(leds);
} //millis
return FRAMETIME;
setPixels(leds);
return FRAMETIME_FIXED * (128-(SEGMENT.speed>>1)); // update only when appropriate time passes (in 42 FPS slots)
} // mode_2Dgameoflife()
/////////////////////////

Wyświetl plik

@ -920,10 +920,11 @@ class WS2812FX {
fadeToBlackBy(CRGB* leds, uint8_t fadeBy),
nscale8(CRGB* leds, uint8_t scale),
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, 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
XY(uint16_t, uint16_t),

Wyświetl plik

@ -334,13 +334,13 @@ void WS2812FX::setPixels(CRGB* leds) {
}
//line function
void WS2812FX::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1,CRGB c) {
uint16_t dx = abs(x1-x0), sx = x0<x1 ? 1 : -1;
uint16_t dy = abs(y1-y0), sy = y0<y1 ? 1 : -1;
uint16_t err = (dx>dy ? dx : -dy)/2, e2;
for(;;){
setPixelColorXY(x0,y0,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;
int16_t dy = abs(y1-y0), sy = y0<y1 ? 1 : -1;
int16_t err = (dx>dy ? dx : -dy)/2, e2;
for (;;) {
if (leds == nullptr) setPixelColorXY(x0,y0,c);
else leds[XY(x0,y0)] = c;
if (x0==x1 && y0==y1) break;
e2 = err;
if (e2 >-dx) { err -= dy; x0 += sx; }

Wyświetl plik

@ -1443,7 +1443,7 @@ const char JSON_mode_names[] PROGMEM = R"=====([
"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 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 Metaballs@Speed;!,!,!;!",
"2D Noise@Speed,Scale;!,!,!;!",

Wyświetl plik

@ -304,7 +304,7 @@ function showErrorToast()
showToast('Connection to light failed!', true);
}
function clearErrorToast(n=10000)
function clearErrorToast(n=5000)
{
var x = gId("toast");
if (x.classList.contains("error")) {
@ -943,7 +943,7 @@ function loadNodes()
return res.json();
})
.then((json)=>{
clearErrorToast();
clearErrorToast(100);
populateNodes(lastinfo, json);
})
.catch((e)=>{
@ -1429,7 +1429,7 @@ function requestJson(command=null)
})
.then(json => {
lastUpdate = new Date();
clearErrorToast();
clearErrorToast(3000);
gId('connind').style.backgroundColor = "var(--c-g)";
if (!json) { showToast('Empty response', true); return; }
if (json.success) return;

Wyświetl plik

@ -278,6 +278,7 @@ bool isAsterisksOnly(const char* str, byte maxLen);
bool requestJSONBufferLock(uint8_t module=255);
void releaseJSONBufferLock();
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
void applyMacro(byte index);

Plik diff jest za duży Load Diff

Wyświetl plik

@ -260,3 +260,15 @@ uint8_t extractModeName(uint8_t mode, const char *src, char *dest, uint8_t maxLe
dest[printedChars] = '\0';
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;
}