class DrainAnimation: public Figment { public: DrainAnimation(Task::State initialState) : Figment("Drain", initialState) {} void loop() override { EVERY_N_MILLISECONDS(8) { m_pos++; m_fillColor.update(); } EVERY_N_MILLISECONDS(50) { if (random(255) >= 10) { m_burst -= m_burst / 10; } } } void handleEvent(const InputEvent& event) override { if (event.intent == InputEvent::SetColor) { m_fillColor = event.asRGB(); } else if (event.intent == InputEvent::Acceleration) { m_pos += log10(event.asInt()); uint16_t burstInc = event.asInt() / 6; m_burst = (m_burst > 0xFFFF - burstInc) ? 0xFFFF : m_burst + burstInc; } } AnimatedRGB m_fillColor; void render(Display* dpy) const override { dpy->clear(); Surface leftPanel{dpy, {0, 0}, {128, 0}}; Surface rightPanel{dpy, {128, 0}, {255, 0}}; fillRange(dpy, leftPanel.start, leftPanel.end, rgb2hsv_approximate(m_fillColor)); fillRange(dpy, rightPanel.end, rightPanel.start, rgb2hsv_approximate(m_fillColor)); } void fillRange(Display* dpy, const PhysicalCoordinates &start, const PhysicalCoordinates& end, const CHSV &baseColor) const { int length = end.x - start.x; int direction = 1; if (length < 0) { direction = -1; } uint8_t frac = 255 / std::abs(length); for(int i = 0; i < std::abs(length); i++) { auto coords = PhysicalCoordinates((start.x + (i * direction)), 0); const uint8_t localScale = inoise8(i * 80, m_pos * 3); const uint8_t dimPosition = lerp8by8(50, 190, scale8(sin8((frac * i) / 2), localScale)); const uint8_t withBurst = ease8InOutCubic(lerp16by16(dimPosition, 255, m_burst)); auto scaledColor = CHSV(baseColor.hue, lerp8by8(100, 255, localScale), withBurst); CRGB src(dpy->pixelAt(coords)); dpy->pixelAt(coords) = blend(scaledColor, src, 200); } } uint16_t m_pos; uint16_t m_burst; };