void life_frame(void) { int x, y; uint8_t sub_frame = life_frame_num++ & 0x1f; static bool reset_next = false; if (sub_frame == 0) { if (reset_next) { life_init(); reset_next = false; } for (y = 0; y < HEIGHT; y++) { for (x = 0; x < WIDTH; x++) { bool alive = life_is_alive(x, y); uint8_t age = life_get_age(x, y); int neighbors = life_calc_neighbors(x, y); // Life rules from: // https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life // 1. Any live cell with fewer than two live neighbours dies, as if // caused by under-population. // 2. Any live cell with two or three live neighbours lives on to // the next generation. // 3. Any live cell with more than three live neighbours dies, as // if by over-population. // 4. Any dead cell with exactly three live neighbours becomes a // live cell, as if by reproduction. if (alive) { if (neighbors == 2 || neighbors == 3) { life_set(x, y, true, age < 0xff ? age + 1 : age); } else { life_set(x, y, false, 0); } } else { if (neighbors == 3) { life_set(x, y, true, 0); } else { life_set(x, y, false, 0); } } } } if (!memcmp(life_alive, life_new_alive, sizeof(life_alive)) || !memcmp(life_last_alive, life_new_alive, sizeof(life_alive))) { reset_next = true; } memcpy(life_last_alive, life_alive, sizeof(life_alive)); memcpy(life_alive, life_new_alive, sizeof(life_alive)); } for (y = 0; y < HEIGHT; y++) { for (x = 0; x < WIDTH; x++) { uint32_t color; if (life_is_alive(x, y)) { int age = life_get_age(x, y); uint32_t index = hsv_inc(life_color_index, age * 0x20 * 4); color = hsv_pixel(index); } else { color = matrix_color(0, 0x00, 0x00); } matrix_set_pixel(x, y, color); } } life_color_index = hsv_inc(life_color_index, 4); }
/** * Perform an animated wipe left-to-right or right-to-left. */ static void wipe(uint8_t stage) { uint8_t last_tick; uint8_t x, y; uint8_t byte, bit; uint8_t index, mask; matrix_color_t color; for (tick = 0, last_tick = 255; tick < MATRIX_WIDTH;) { if (last_tick == tick) continue; last_tick = tick; if (button_get_aux_state()) button_pressed = 1; if (stage == 2) x = MATRIX_WIDTH - 1 - last_tick; // wipe right to left else x = last_tick; // wipe left to right byte = x / 8; bit = x % 8; mask = 1 << bit; for (y=0; y<MATRIX_HEIGHT; ++y) { index = (MATRIX_HEIGHT - 1 - y) * ROW_BYTES + byte; if (stage == 3) { color.red = 0; color.green = 0; } else { color.red = (pgm_read_byte(&vhs[index]) & mask) ? 255 : 0; index += ROW_BYTES / 2; // move from red to green data color.green = (pgm_read_byte(&vhs[index]) & mask) ? 255 : 0; if (stage == 2) { // time to cycle some colors: if (color.red) { if (color.green) color.red = 0; // yellow -> green else color.green = 255; // red -> yellow } else { if (color.green) { color.red = 255; // green -> red color.green = 0; } } } } matrix_set_pixel(x, y, color); } } }