#pragma once #include "effects/Common.h" #include "helpers/ColorRGBW.h" #include "helpers/ColorHSV.h" #include "helpers/ColorConversions.h" #include "helpers/BellCurve.h" struct EffectAlexaSwipeConfig { float primaryColorWidth; // in degrees float transitionWidth; float swipeSpeed; // in degrees per second float bellCurveWidthInLeds; float startPosition; bool forward; ColorRGBW primaryColor; ColorRGBW secondaryColor; }; template class EffectAlexaSwipe { public: static constexpr auto NUM_LEDS = numLeds(); static constexpr int DELAY_MS = 10; using ConfigType = EffectAlexaSwipeConfig; EffectAlexaSwipe(const EffectAlexaSwipeConfig &cfg, TLedStrip &ledStrip) : ledStrip_(ledStrip), currentPosition_(0), transitionWidth_(cfg.transitionWidth / 360.0f * NUM_LEDS), invTransitionWidth_(1.0f / transitionWidth_), primaryColorWidth_(cfg.primaryColorWidth / 360.0f * NUM_LEDS + cfg.bellCurveWidthInLeds), bellCurveWidth_(cfg.bellCurveWidthInLeds), invBellCurveWidth_(1.0f / cfg.bellCurveWidthInLeds), speed_(cfg.swipeSpeed / 360 / 1000 * NUM_LEDS * DELAY_MS), startPosition_(cfg.startPosition / 360.0f * NUM_LEDS), primaryColor_(rgb2hsv(cfg.primaryColor)), secondaryColor_(rgb2hsv(cfg.secondaryColor)) { if (cfg.forward) { currentPosition_ = 0; direction_ = 1; } else { currentPosition_ = float(NUM_LEDS) / 2.0f + bellCurveWidth_ / 2; direction_ = -1; } } int operator()() { clear(ledStrip_); const auto width = std::min(int(currentPosition_ + 1), int(NUM_LEDS / 2)); setLedRGBW(ledStrip_, startPosition_, getColor(currentPosition_)); for (int i = 1; i < width; ++i) { const float x = currentPosition_ - float(i); if (x > 0.0f) { const int led1 = startPosition_ + i; const int led2 = startPosition_ - i; const ColorRGBW color = getColor(x); setLedRGBW(ledStrip_, led1, color); setLedRGBW(ledStrip_, led2, color); } } currentPosition_ += direction_ * speed_; currentPosition_ = std::min(currentPosition_, float(NUM_LEDS) / 2.0f + bellCurveWidth_ / 2); currentPosition_ = std::max(currentPosition_, 0.0f); return DELAY_MS; } private: void getParams(float x, float &interpFac, float &brightness) { brightness = (x < bellCurveWidth_) ? bellCurveApproximation(bellCurveWidth_ / 2 - x, invBellCurveWidth_) : 1.0f; if (x < primaryColorWidth_) interpFac = 0.0f; else if (x > primaryColorWidth_ + transitionWidth_) interpFac = 1.0f; else interpFac = (x - primaryColorWidth_) * invTransitionWidth_; } // x is positive distance from running front ColorRGBW getColor(float x) { float interpFac; float brightness; getParams(x, interpFac, brightness); ColorHSV result{ interpFac * secondaryColor_.h + (1.0f - interpFac) * primaryColor_.h, interpFac * secondaryColor_.s + (1.0f - interpFac) * primaryColor_.s, interpFac * secondaryColor_.v + (1.0f - interpFac) * primaryColor_.v}; result.v *= brightness; return hsv2rgb(result); } TLedStrip &ledStrip_; // in number of leds float currentPosition_; float transitionWidth_; float invTransitionWidth_; float primaryColorWidth_; float bellCurveWidth_; float invBellCurveWidth_; float speed_; int startPosition_; const ColorHSV primaryColor_; const ColorHSV secondaryColor_; float direction_; }; // Traits template <> struct EffectIdToConfig { using type = EffectAlexaSwipeConfig; }; template <> struct EffectConfigToId { static constexpr auto id = EffectId::ALEXA_SWIPE; }; template struct EffectIdToClass { using type = EffectAlexaSwipe; };