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
@ -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,36 +4552,21 @@ 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);
|
||||
|
||||
if (SEGENV.call == 0) fill_solid(leds, CRGB::Black);
|
||||
|
||||
//slow down based on speed parameter
|
||||
if (now - SEGENV.step >= ((255-SEGMENT.speed)*4U)) {
|
||||
SEGENV.step = 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];
|
||||
CRGB *prevLeds = reinterpret_cast<CRGB*>(SEGENV.data) + dataSize;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
//reset leds if effect repeats (wait 3 seconds after repetition)
|
||||
if (now - resetMillis > 3000) {
|
||||
if (SEGENV.call == 0 || now - resetMillis > 20000) {
|
||||
resetMillis = now;
|
||||
|
||||
random16_set_seed(now); //seed the random generator
|
||||
@ -4591,37 +4577,44 @@ uint16_t WS2812FX::mode_2Dgameoflife(void) { // Written by Ewoud Wijma, inspired
|
||||
if (state == 0)
|
||||
leds[XY(x,y)] = backgroundColor;
|
||||
else
|
||||
leds[XY(x,y)] = SEGMENT.intensity < 128?(CRGB)color_wheel(random8()):CRGB(random8(), random8(), random8());
|
||||
leds[XY(x,y)] = (CRGB)color_from_palette(random8(), false, PALETTE_SOLID_WRAP, 0);
|
||||
}
|
||||
|
||||
//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;
|
||||
fill_solid(prevLeds, CRGB::Black);
|
||||
|
||||
} else {
|
||||
SEGENV.aux1 = 0;
|
||||
SEGENV.aux0 = 0xFFFF;
|
||||
}
|
||||
|
||||
//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)];
|
||||
|
||||
//calculate new leds
|
||||
for (int x = 1; x < width-1; x++) for (int y = 1; y < height-1; y++) {
|
||||
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
|
||||
|
||||
//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
|
||||
// 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
|
||||
|
||||
// count different neighbours and colors, except the centre cell
|
||||
if (xy != XY(x,y) && leds[xy] != backgroundColor) {
|
||||
if (xy != XY(x,y) && prevLeds[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++;
|
||||
int k;
|
||||
for (k=0; k<9 && colorsCount[i].count != 0; k++)
|
||||
if (colorsCount[k].color == prevLeds[xy]) {
|
||||
colorsCount[k].count++;
|
||||
colorFound = true;
|
||||
}
|
||||
|
||||
if (!colorFound) colorsCount[i] = {leds[xy], 1}; //add new color found in the array
|
||||
if (!colorFound) colorsCount[k] = {prevLeds[xy], 1}; //add new color found in the array
|
||||
}
|
||||
} // i,j
|
||||
|
||||
@ -4638,27 +4631,16 @@ uint16_t WS2812FX::mode_2Dgameoflife(void) { // Written by Ewoud Wijma, inspired
|
||||
// else do nothing!
|
||||
} //x,y
|
||||
|
||||
//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);
|
||||
|
||||
//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;
|
||||
|
||||
//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
|
||||
// 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;
|
||||
|
||||
setPixels(leds);
|
||||
} //millis
|
||||
|
||||
return FRAMETIME;
|
||||
return FRAMETIME_FIXED * (128-(SEGMENT.speed>>1)); // update only when appropriate time passes (in 42 FPS slots)
|
||||
} // mode_2Dgameoflife()
|
||||
|
||||
/////////////////////////
|
||||
|
@ -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),
|
||||
|
@ -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; }
|
||||
|
@ -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;!,!,!;!",
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
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';
|
||||
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