@@ -5173,50 +5173,54 @@ uint16_t mode_2Dgameoflife(void) { // Written by Ewoud Wijma, inspired by https:
51735173 const uint16_t rows = SEGMENT.virtualHeight ();
51745174 const size_t dataSize = ((SEGMENT.length () + 7 ) / 8 ); // round up to nearest byte
51755175 const size_t detectionSize = sizeof (uint8_t ) + sizeof (uint16_t )*2 ; // 1 uint8_t (gliderLen), 2 uint16_t (2 CRCs)
5176- const size_t totalSize = dataSize * 2 + detectionSize + sizeof (CRGB); // CRGB prevColor
5176+ const size_t totalSize = dataSize * 2 + detectionSize + sizeof (uint8_t );
51775177
51785178 if (!SEGENV.allocateData (totalSize)) return mode_static (); // allocation failed
5179- byte *cells = reinterpret_cast <byte*>(SEGENV.data );
5179+ byte *cells = reinterpret_cast <byte*>(SEGENV.data );
51805180 byte *futureCells = reinterpret_cast <byte*>(SEGENV.data + dataSize);
5181- uint8_t *gliderLength = reinterpret_cast <uint8_t *>(SEGENV.data + dataSize*2 );
5181+ uint8_t *gliderLength = reinterpret_cast <uint8_t *>(SEGENV.data + dataSize*2 );
51825182 uint16_t *oscillatorCRC = reinterpret_cast <uint16_t *>(SEGENV.data + dataSize*2 + sizeof (uint8_t ));
5183- uint16_t *spaceshipCRC = reinterpret_cast <uint16_t *>(SEGENV.data + dataSize*2 + sizeof (uint8_t ) + sizeof (uint16_t ));
5184- CRGB *prevColor = reinterpret_cast <CRGB*>(SEGENV.data + dataSize*2 + detectionSize);
5185-
5186- uint16_t &generation = SEGENV.aux0 ; // rename aux0 readability (not needed)
5187- CRGB bgColor = SEGCOLOR (1 );
5188- CRGB color;
5183+ uint16_t *spaceshipCRC = reinterpret_cast <uint16_t *>(SEGENV.data + dataSize*2 + sizeof (uint8_t ) + sizeof (uint16_t ));
5184+ uint8_t *prevPalette = reinterpret_cast <uint8_t *>(SEGENV.data + dataSize*2 + detectionSize);
5185+
5186+ uint16_t &generation = SEGENV.aux0 ; // Rename SEGENV/SEGMENT variables for readability
5187+ bool allColors = SEGMENT.check1 ;
5188+ bool overlayBG = SEGMENT.check2 ;
5189+ bool wrap = SEGMENT.check3 ;
5190+ byte blur = map (SEGMENT.custom1 , 0 , 255 , 255 , 0 );
5191+ bool bgBlendMode = SEGMENT.custom1 > 220 && !overlayBG; // if blur is high and not overlaying, use bg blend mode
5192+ byte bgBlur = map (SEGMENT.custom1 - 220 , 0 , 35 , 255 , 128 );
5193+ CRGB bgColor = SEGCOLOR (1 );
5194+ CRGB color = allColors ? random16 () * random16 () : SEGMENT.color_from_palette (0 , false , PALETTE_SOLID_WRAP, 0 );
51895195 uint16_t cIndex;
51905196
51915197 if (SEGENV.call == 0 ) {
51925198 SEGMENT.setUpLeds ();
51935199 SEGMENT.fill (BLACK); // to make sure that segment buffer and physical leds are aligned initially
51945200 }
5195- // start new game of life
5201+ // Setup New Game of Life
51965202 if ((SEGENV.call == 0 || generation == 0 ) && SEGENV.step < strip.now ) {
51975203 SEGENV.step = strip.now + 1250 ; // show initial state for 1.25 seconds
51985204 generation = 1 ;
5205+ *prevPalette = SEGMENT.palette ;
51995206 random16_set_seed (strip.now >>2 ); // seed the random generator
52005207 // Setup Grid
5208+ memset (cells, 0 , dataSize);
52015209 for (int x = 0 ; x < cols; x++) for (int y = 0 ; y < rows; y++) {
52025210 cIndex = y * cols + x;
5203- if (random8 () < 82 ) { // ~32% chance of being alive
5211+ if (random8 (100 ) < 32 ) { // ~32% chance of being alive
52045212 setBitValue (cells, cIndex, true );
5205- setBitValue (futureCells, cIndex, true );
52065213 color = SEGMENT.color_from_palette (random8 (), false , PALETTE_SOLID_WRAP, 0 );
5207- SEGMENT.setPixelColorXY (x,y,!SEGMENT.check1 ?color : RGBW32 (color.r , color.g , color.b , 0 ));
5208- }
5209- else {
5210- setBitValue (cells, cIndex, false );
5211- setBitValue (futureCells, cIndex, false );
5212- if (SEGMENT.check2 ) continue ; // overlay
5213- SEGMENT.setPixelColorXY (x,y, !SEGMENT.check1 ?bgColor : RGBW32 (bgColor.r , bgColor.g , bgColor.b , 0 ));
5214+ SEGMENT.setPixelColorXY (x,y, allColors ? random16 () * random16 () : color);
52145215 }
5216+ else if (!overlayBG) SEGMENT.setPixelColorXY (x,y, allColors ? RGBW32 (bgColor.r , bgColor.g , bgColor.b , 0 ) : bgColor); // set background color if not overlaying
52155217 }
5216-
5217- // Clear CRCs
5218- *oscillatorCRC = 0 ;
5219- *spaceshipCRC = 0 ;
5218+ memcpy (futureCells, cells, dataSize);
5219+
5220+ // Set CRCs
5221+ uint16_t crc = crc16 ((const unsigned char *)cells, dataSize);
5222+ *oscillatorCRC = crc;
5223+ *spaceshipCRC = crc;
52205224
52215225 // Calculate glider length LCM(rows,cols)*4
52225226 uint8_t a = rows;
@@ -5229,32 +5233,27 @@ uint16_t mode_2Dgameoflife(void) { // Written by Ewoud Wijma, inspired by https:
52295233 *gliderLength = cols * rows / a * 4 ;
52305234 return FRAMETIME;
52315235 }
5232- // Redraw immediately if overlay to avoid flicker
5233- if (SEGMENT.check2 ) {
5234- for (int x = 0 ; x < cols; x++) for (int y = 0 ; y < rows; y++) {
5235- // redraw foreground/alive
5236- cIndex = y * cols + x;
5237- if (getBitValue (cells, cIndex)) {
5238- color = SEGMENT.getPixelColorXY (x,y);
5239- SEGMENT.setPixelColorXY (x,y, !SEGMENT.check1 ?color : RGBW32 (color.r , color.g , color.b , 0 ));
5240- }
5241- }
5242- }
5243- if (SEGENV.step > strip.now || strip.now - SEGENV.step < 1000 / (uint32_t )map (SEGMENT.speed ,0 ,255 ,1 ,64 )) { // 1 - 64 updates per second
5244- return FRAMETIME; // skip if not enough time has passed
5245- }
52465236
5247- // Recolor live cells if palette/color changed
5248- if (SEGMENT.color_from_palette (0 , false , PALETTE_SOLID_WRAP, 0 ) != *prevColor){
5237+ // Redraw if paused (remove blur), palette changed, or overlaying background (avoid flicker)
5238+ bool palChanged = SEGMENT.palette != *prevPalette && !allColors;
5239+ bool blurDead = SEGENV.step > strip.now && !bgBlendMode && !overlayBG;
5240+ if (palChanged || blurDead || overlayBG) {
52495241 for (int x = 0 ; x < cols; x++) for (int y = 0 ; y < rows; y++) {
52505242 cIndex = y * cols + x;
5251- if (getBitValue (cells, cIndex)) {
5252- SEGMENT.setPixelColorXY (x,y, SEGMENT.color_from_palette (random8 (), false , PALETTE_SOLID_WRAP, 0 ));
5243+ bool alive = getBitValue (cells, cIndex);
5244+ if (palChanged && alive) SEGMENT.setPixelColorXY (x,y, SEGMENT.color_from_palette (random8 (), false , PALETTE_SOLID_WRAP, 0 ));
5245+ else if (overlayBG & alive) {
5246+ color = SEGMENT.getPixelColorXY (x,y);
5247+ SEGMENT.setPixelColorXY (x,y, allColors ? RGBW32 (color.r , color.g , color.b , 0 ) : color);
52535248 }
5249+ if (palChanged && !alive && !overlayBG) SEGMENT.setPixelColorXY (x,y, bgColor); // remove blurred cells from previous palette
5250+ else if (blurDead && !alive) SEGMENT.setPixelColorXY (x,y, blend (SEGMENT.getPixelColorXY (x,y), bgColor, blur));
52545251 }
5255- *prevColor = SEGMENT.color_from_palette ( 0 , false , PALETTE_SOLID_WRAP, 0 ) ;
5252+ if (palChanged) *prevPalette = SEGMENT.palette ;
52565253 }
52575254
5255+ if (SEGENV.step > strip.now || strip.now - SEGENV.step < 1000 / (uint32_t )map (SEGMENT.speed ,0 ,255 ,1 ,64 )) return FRAMETIME; // skip if not enough time has passed (1-64 updates/sec)
5256+
52585257 // Update Game of Life
52595258 bool cellChanged = false ; // Detect still live and dead grids
52605259 // cell coordinates
@@ -5268,7 +5267,7 @@ uint16_t mode_2Dgameoflife(void) { // Written by Ewoud Wijma, inspired by https:
52685267
52695268 for (int i = -1 ; i <= 1 ; i++) for (int j = -1 ; j <= 1 ; j++) { // iterate through 3*3 matrix
52705269 if (i==0 && j==0 ) continue ; // ignore itself
5271- if (!SEGMENT. check3 || generation % 1500 == 0 ) { // no wrap, disable wrap every 1500 generations to prevent undetected repeats
5270+ if (!wrap || generation % 1500 == 0 ) { // no wrap, disable wrap every 1500 generations to prevent undetected repeats
52725271 cX = x+i;
52735272 cY = y+j;
52745273 if (cX < 0 || cY < 0 || cX >= cols || cY >= rows) continue ; // skip if out of bounds
@@ -5292,34 +5291,33 @@ uint16_t mode_2Dgameoflife(void) { // Written by Ewoud Wijma, inspired by https:
52925291 cIndex = y * cols + x; // current cell index
52935292 bool cellValue = getBitValue (cells, cIndex);
52945293 if ((cellValue) && (neighbors < 2 || neighbors > 3 )) {
5295- // Loneliness or overpopulation
5294+ // Loneliness or Overpopulation
52965295 cellChanged = true ;
52975296 setBitValue (futureCells, cIndex, false );
5298- // blur /turn off dying cells
5299- if (!SEGMENT. check2 ) SEGMENT.setPixelColorXY (x,y, blend (SEGMENT.getPixelColorXY (x,y), bgColor, map (SEGMENT. custom1 , 0 , 255 , 255 , 0 ) ));
5297+ // Blur /turn off dying cells
5298+ if (!overlayBG ) SEGMENT.setPixelColorXY (x,y, blend (SEGMENT.getPixelColorXY (x,y), bgColor, bgBlendMode ? bgBlur : blur ));
53005299 }
53015300 else if (!(cellValue) && (neighbors == 3 )) {
53025301 // Reproduction
53035302 setBitValue (futureCells, cIndex, true );
53045303 cellChanged = true ;
5305- // find dominant color and assign it to a cell
5306- // no longer storing colors, if parent dies the color is lost
5307- CRGB dominantColor;
5304+ // find dominant color and assign it to a new born cell no longer storing colors, if parent dies the color is lost
5305+ CRGB dominantColor;
53085306 if (colorCount == 3 ) { // All parents survived
53095307 if ((nColors[0 ] == nColors[1 ]) || (nColors[0 ] == nColors[2 ])) dominantColor = nColors[0 ];
53105308 else if (nColors[1 ] == nColors[2 ]) dominantColor = nColors[1 ];
5311- else dominantColor = nColors[random8 ()% 3 ];
5309+ else dominantColor = nColors[random8 (3 ) ];
53125310 }
5313- else if (colorCount == 2 ) dominantColor = nColors[random8 ()% 2 ]; // 1 leading parent died
5314- else if (colorCount == 1 ) dominantColor = nColors[0 ]; // 2 leading parents died
5315- else dominantColor = color; // all parents died last used color
5311+ else if (colorCount == 2 ) dominantColor = nColors[random8 (2 ) ]; // 1 leading parent died
5312+ else if (colorCount == 1 ) dominantColor = nColors[0 ]; // 2 leading parents died
5313+ else dominantColor = color; // all parents died last used color
53165314 // mutate color chance
5317- if (random8 () < SEGMENT. intensity || dominantColor == bgColor) dominantColor = !SEGMENT. check1 ?SEGMENT. color_from_palette ( random8 (), false , PALETTE_SOLID_WRAP , 0 ): random16 ()* random16 ();
5318- if (SEGMENT.check1 ) dominantColor = RGBW32 (dominantColor. r , dominantColor. g , dominantColor. b , 0 ); // WLEDMM support all colors
5315+ if (allColors) dominantColor = RGBW32 ( dominantColor. r , dominantColor. g , dominantColor. b , 0 ); // WLEDMM support all colors
5316+ if (random8 () < SEGMENT.intensity || dominantColor == bgColor ) dominantColor = allColors ? random16 () * random16 () : SEGMENT. color_from_palette ( random8 (), false , PALETTE_SOLID_WRAP , 0 );
53195317 SEGMENT.setPixelColorXY (x,y, dominantColor);
53205318 }
53215319 else { // blur dead cells
5322- if (!cellValue && !SEGMENT. check2 ) SEGMENT.setPixelColorXY (x,y, blend (SEGMENT.getPixelColorXY (x,y), bgColor, map (SEGMENT. custom1 , 0 , 255 , 255 , 0 ) ));
5320+ if (!cellValue && !overlayBG && !bgBlendMode ) SEGMENT.setPixelColorXY (x,y, blend (SEGMENT.getPixelColorXY (x,y), bgColor, bgBlendMode ? bgBlur : blur ));
53235321 }
53245322 }
53255323 // update cell values
@@ -5343,7 +5341,7 @@ uint16_t mode_2Dgameoflife(void) { // Written by Ewoud Wijma, inspired by https:
53435341 SEGENV.step = strip.now ;
53445342 return FRAMETIME;
53455343} // mode_2Dgameoflife()
5346- static const char _data_FX_MODE_2DGAMEOFLIFE[] PROGMEM = " Game Of Life@!,Color Mutation ☾,Blur ☾,,,All Colors ☾,Overlay ☾,Wrap ☾,;!,!;!;2;sx=82,ix=12 ,c1=8 ,o3=1" ;
5344+ static const char _data_FX_MODE_2DGAMEOFLIFE[] PROGMEM = " Game Of Life@!,Color Mutation ☾,Blur ☾,,,All Colors ☾,Overlay BG ☾,Wrap ☾,;!,!;!;2;sx=82,ix=4 ,c1=48,o1=0,o2=0 ,o3=1" ;
53475345
53485346// ///////////////////////
53495347// 2D Hiphotic //
0 commit comments