Public Access
Add four animated Cyberpunk-style ESPHome pages
Netrunner HUD, self-solving breach protocol, optics boot-and-scan and a split HUD with a mini breach matrix, all in the page rotation. The el512 display gains animated_pages / animation_interval (redraw ~15 fps while shown), page_age_ms() as animation clock, and shift_rows() / invert_rect() for glitch effects. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
6d5e5315f0
commit
50ee17b3f6
7 files changed
+944
-4
No files matched your search
@@ -1,5 +1,8 @@
|
||||
#include "el512_display.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
#include <esp_heap_caps.h>
|
||||
#include <esp_private/esp_clk.h>
|
||||
|
||||
@@ -26,10 +29,21 @@ void EL512Display::loop() {
|
||||
if (this->panel_ == nullptr || !this->panel_->running())
|
||||
return;
|
||||
this->check_refresh_health_();
|
||||
const uint32_t now = millis();
|
||||
this->page_age_ms(); // notice page changes even when nothing draws
|
||||
if (now - this->animated_at_ >= this->animation_interval_) {
|
||||
const auto *page = this->get_active_page();
|
||||
for (const auto *p : this->animated_pages_) {
|
||||
if (p == page) {
|
||||
this->animated_at_ = now;
|
||||
this->update();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this->still_alive_page_ == nullptr)
|
||||
return;
|
||||
const bool active = this->is_still_alive_playing();
|
||||
const uint32_t now = millis();
|
||||
if (active && !this->still_alive_was_active_) {
|
||||
// Remember where we came from, then start the show from the top.
|
||||
this->still_alive_return_ = this->previous_page_ != this->still_alive_page_ ? this->previous_page_ : nullptr;
|
||||
@@ -94,6 +108,46 @@ void EL512Display::draw_still_alive() {
|
||||
this->still_alive_.draw(*this->panel_);
|
||||
}
|
||||
|
||||
uint32_t EL512Display::page_age_ms() {
|
||||
const uint32_t now = millis();
|
||||
if (this->get_active_page() != this->age_page_) {
|
||||
this->age_page_ = this->get_active_page();
|
||||
this->age_start_ = now;
|
||||
}
|
||||
return now - this->age_start_;
|
||||
}
|
||||
|
||||
void EL512Display::shift_rows(int y, int height, int dx) {
|
||||
if (this->panel_ == nullptr)
|
||||
return;
|
||||
constexpr int W = EL512Panel::WIDTH, ROW = W / 8;
|
||||
dx %= W;
|
||||
if (dx < 0)
|
||||
dx += W;
|
||||
if (dx == 0)
|
||||
return;
|
||||
uint8_t *fb = this->panel_->framebuffer();
|
||||
uint8_t src[ROW];
|
||||
for (int r = std::max(y, 0); r < std::min(y + height, (int) EL512Panel::HEIGHT); r++) {
|
||||
uint8_t *row = fb + r * ROW;
|
||||
memcpy(src, row, ROW);
|
||||
memset(row, 0, ROW);
|
||||
for (int x = 0; x < W; x++) {
|
||||
const int s = (x - dx + W) % W;
|
||||
if (src[s >> 3] & (0x80 >> (s & 7)))
|
||||
row[x >> 3] |= 0x80 >> (x & 7);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EL512Display::invert_rect(int x, int y, int width, int height) {
|
||||
if (this->panel_ == nullptr)
|
||||
return;
|
||||
for (int py = y; py < y + height; py++)
|
||||
for (int px = x; px < x + width; px++)
|
||||
this->panel_->setPixel(px, py, !this->panel_->getPixel(px, py));
|
||||
}
|
||||
|
||||
void EL512Display::update() {
|
||||
if (this->panel_ == nullptr || !this->panel_->running())
|
||||
return;
|
||||
|
||||
Reference in new issue
Block a user