musicmouse/espmusicmouse/lib/ledtl/effects/AlexaSwipe.h

141 lines
3.8 KiB
C
Raw Normal View History

2021-11-19 17:22:09 +01:00
#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;
2021-11-19 17:28:48 +01:00
bool forward;
2021-11-19 17:22:09 +01:00
ColorRGBW primaryColor;
ColorRGBW secondaryColor;
};
template <typename TLedStrip>
class EffectAlexaSwipe
{
public:
static constexpr auto NUM_LEDS = numLeds<TLedStrip>();
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))
{
2021-11-19 17:28:48 +01:00
if (cfg.forward)
{
currentPosition_ = 0;
direction_ = 1;
}
else
{
currentPosition_ = float(NUM_LEDS) / 2.0f + bellCurveWidth_ / 2;
direction_ = -1;
}
2021-11-19 17:22:09 +01:00
}
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);
}
}
2021-11-19 17:28:48 +01:00
currentPosition_ += direction_ * speed_;
2021-11-19 17:22:09 +01:00
currentPosition_ = std::min(currentPosition_, float(NUM_LEDS) / 2.0f + bellCurveWidth_ / 2);
2021-11-19 17:28:48 +01:00
currentPosition_ = std::max(currentPosition_, 0.0f);
2021-11-19 17:22:09 +01:00
return DELAY_MS;
}
2021-11-19 17:28:48 +01:00
private:
2021-11-19 17:22:09 +01:00
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;
2021-11-19 17:28:48 +01:00
return hsv2rgb(result);
2021-11-19 17:22:09 +01:00
}
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_;
2021-11-19 17:28:48 +01:00
float direction_;
2021-11-19 17:22:09 +01:00
};
// Traits
template <>
struct EffectIdToConfig<EffectId::ALEXA_SWIPE>
{
using type = EffectAlexaSwipeConfig;
};
template <>
struct EffectConfigToId<EffectAlexaSwipeConfig>
{
static constexpr auto id = EffectId::ALEXA_SWIPE;
};
template <typename TLedStrip>
struct EffectIdToClass<EffectId::ALEXA_SWIPE, TLedStrip>
{
using type = EffectAlexaSwipe<TLedStrip>;
};