Color interpolation effect
This commit is contained in:
parent
0bbb5d278c
commit
da9a96fdfa
|
@ -26,6 +26,15 @@ public:
|
||||||
data_[idx] = (g << 0) | (r << 8) | (b << 16) | (w << 24);
|
data_[idx] = (g << 0) | (r << 8) | (b << 16) | (w << 24);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void getRGBW(int idx, uint8_t &r, uint8_t &g, uint8_t &b, uint8_t &w)
|
||||||
|
{
|
||||||
|
idx = normalizeIdx(idx);
|
||||||
|
g = (data_[idx] >> 0) & 0xff;
|
||||||
|
r = (data_[idx] >> 8) & 0xff;
|
||||||
|
b = (data_[idx] >> 16) & 0xff;
|
||||||
|
w = (data_[idx] >> 24) & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
const uint32_t *rawData() const { return data_; }
|
const uint32_t *rawData() const { return data_; }
|
||||||
constexpr static int numLeds() { return TNumLeds; }
|
constexpr static int numLeds() { return TNumLeds; }
|
||||||
|
|
||||||
|
@ -89,4 +98,12 @@ void clear(LedStripRGBW<TNumLeds> &s)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < TNumLeds; ++i)
|
for (int i = 0; i < TNumLeds; ++i)
|
||||||
s.set(i, 0, 0, 0, 0);
|
s.set(i, 0, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <int TNumLeds>
|
||||||
|
ColorRGBW getLedRGBW(LedStripRGBW<TNumLeds> &s, int idx)
|
||||||
|
{
|
||||||
|
ColorRGBW res;
|
||||||
|
s.getRGBW(idx, res.r, res.g, res.b, res.w);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
|
@ -50,10 +50,6 @@ public:
|
||||||
currentPosition_ = float(NUM_LEDS) / 2.0f + bellCurveWidth_ / 2;
|
currentPosition_ = float(NUM_LEDS) / 2.0f + bellCurveWidth_ / 2;
|
||||||
direction_ = -1;
|
direction_ = -1;
|
||||||
}
|
}
|
||||||
//#ifndef PLATFORM_NATIVE
|
|
||||||
// Serial.printf("Primary color %f, %f, %f\n", primaryColor_.h, primaryColor_.s, primaryColor_.v);
|
|
||||||
// Serial.printf("Secondary color %f, %f, %f\n", secondaryColor_.h, secondaryColor_.s, secondaryColor_.v);
|
|
||||||
//#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int operator()()
|
int operator()()
|
||||||
|
|
|
@ -5,6 +5,7 @@ enum class EffectId
|
||||||
STATIC,
|
STATIC,
|
||||||
CIRCULAR,
|
CIRCULAR,
|
||||||
ALEXA_SWIPE,
|
ALEXA_SWIPE,
|
||||||
|
RANDOM_TWO_COLOR_INTERPOLATION
|
||||||
};
|
};
|
||||||
|
|
||||||
template <EffectId id>
|
template <EffectId id>
|
||||||
|
|
|
@ -0,0 +1,146 @@
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "effects/Common.h"
|
||||||
|
#include "helpers/ColorRGBW.h"
|
||||||
|
#include "helpers/ColorHSV.h"
|
||||||
|
#include "helpers/ColorConversions.h"
|
||||||
|
|
||||||
|
struct EffectRandomTwoColorInterpolationConfig
|
||||||
|
{
|
||||||
|
int cycleDurationMs;
|
||||||
|
bool startWithExisting;
|
||||||
|
int numSegments;
|
||||||
|
|
||||||
|
ColorHSV color1;
|
||||||
|
ColorHSV color2;
|
||||||
|
|
||||||
|
bool hue1Random;
|
||||||
|
bool hue2Random;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename TLedStrip>
|
||||||
|
class EffectRandomTwoColorInterpolation
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static constexpr auto NUM_LEDS = numLeds<TLedStrip>();
|
||||||
|
static constexpr int DELAY_MS = 10;
|
||||||
|
|
||||||
|
EffectRandomTwoColorInterpolation(const EffectRandomTwoColorInterpolationConfig &cfg, TLedStrip &ledStrip)
|
||||||
|
: ledStrip_(ledStrip),
|
||||||
|
config_(cfg),
|
||||||
|
progress_(0.0f)
|
||||||
|
{
|
||||||
|
currentColors_ = arr1;
|
||||||
|
nextColors_ = arr2;
|
||||||
|
|
||||||
|
if (config_.startWithExisting)
|
||||||
|
for (int i = 0; i < NUM_LEDS; ++i)
|
||||||
|
currentColors_[i] = rgb2hsv(getLedRGBW(ledStrip_, i));
|
||||||
|
else
|
||||||
|
randomizeColors(currentColors_);
|
||||||
|
|
||||||
|
randomizeColors(nextColors_);
|
||||||
|
}
|
||||||
|
|
||||||
|
int operator()()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < NUM_LEDS; ++i)
|
||||||
|
setLedRGBW(ledStrip_, i, hsv2rgb(interpolate(currentColors_[i], nextColors_[i], progress_)));
|
||||||
|
|
||||||
|
progress_ += (float(DELAY_MS) / config_.cycleDurationMs);
|
||||||
|
if (progress_ > 1)
|
||||||
|
{
|
||||||
|
progress_ = 0;
|
||||||
|
std::swap(currentColors_, nextColors_);
|
||||||
|
randomizeColors(nextColors_);
|
||||||
|
}
|
||||||
|
return DELAY_MS;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
float randomFloat()
|
||||||
|
{
|
||||||
|
return float(esp_random()) / float(UINT32_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
ColorHSV randomColor()
|
||||||
|
{
|
||||||
|
ColorHSV color1 = config_.color1;
|
||||||
|
ColorHSV color2 = config_.color2;
|
||||||
|
|
||||||
|
if (config_.hue1Random)
|
||||||
|
color1.h = randomFloat() * 360;
|
||||||
|
if (config_.hue2Random)
|
||||||
|
color2.h = randomFloat() * 360;
|
||||||
|
|
||||||
|
float f = randomFloat();
|
||||||
|
return interpolate(color1, color2, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void randomizeColors(ColorHSV *arr)
|
||||||
|
{
|
||||||
|
int segmentLength = NUM_LEDS / config_.numSegments;
|
||||||
|
int lastSegmentLength = NUM_LEDS - (segmentLength * (config_.numSegments - 1));
|
||||||
|
|
||||||
|
ColorHSV firstColor = randomColor();
|
||||||
|
|
||||||
|
ColorHSV currentColor = firstColor;
|
||||||
|
ColorHSV nextColor = randomColor();
|
||||||
|
|
||||||
|
int position = random(0, NUM_LEDS);
|
||||||
|
const auto incrPosition = [&position]()
|
||||||
|
{
|
||||||
|
position = (position == NUM_LEDS - 1) ? 0 : position + 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int segmentIdx = 0; segmentIdx < config_.numSegments - 1; ++segmentIdx)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < segmentLength; ++i)
|
||||||
|
{
|
||||||
|
float f = float(i) / float(segmentLength);
|
||||||
|
arr[position] = interpolate(currentColor, nextColor, f);
|
||||||
|
incrPosition();
|
||||||
|
}
|
||||||
|
currentColor = nextColor;
|
||||||
|
nextColor = randomColor();
|
||||||
|
}
|
||||||
|
// last segment
|
||||||
|
for (int i = 0; i < lastSegmentLength; ++i)
|
||||||
|
{
|
||||||
|
float f = float(i) / float(lastSegmentLength);
|
||||||
|
arr[position] = interpolate(currentColor, firstColor, f);
|
||||||
|
incrPosition();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TLedStrip &ledStrip_;
|
||||||
|
EffectRandomTwoColorInterpolationConfig config_;
|
||||||
|
|
||||||
|
ColorHSV arr1[NUM_LEDS];
|
||||||
|
ColorHSV arr2[NUM_LEDS];
|
||||||
|
|
||||||
|
ColorHSV *currentColors_;
|
||||||
|
ColorHSV *nextColors_;
|
||||||
|
|
||||||
|
float progress_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Traits
|
||||||
|
template <>
|
||||||
|
struct EffectIdToConfig<EffectId::RANDOM_TWO_COLOR_INTERPOLATION>
|
||||||
|
{
|
||||||
|
using type = EffectRandomTwoColorInterpolationConfig;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct EffectConfigToId<EffectRandomTwoColorInterpolationConfig>
|
||||||
|
{
|
||||||
|
static constexpr auto id = EffectId::RANDOM_TWO_COLOR_INTERPOLATION;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename TLedStrip>
|
||||||
|
struct EffectIdToClass<EffectId::RANDOM_TWO_COLOR_INTERPOLATION, TLedStrip>
|
||||||
|
{
|
||||||
|
using type = EffectRandomTwoColorInterpolation<TLedStrip>;
|
||||||
|
};
|
|
@ -1,3 +1,5 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
#include "helpers/ColorHSV.h"
|
#include "helpers/ColorHSV.h"
|
||||||
#include "helpers/ColorRGBW.h"
|
#include "helpers/ColorRGBW.h"
|
||||||
|
|
||||||
|
|
|
@ -5,4 +5,42 @@
|
||||||
struct ColorHSV
|
struct ColorHSV
|
||||||
{
|
{
|
||||||
float h, s, v;
|
float h, s, v;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline ColorHSV operator*(const ColorHSV &c, float scalar)
|
||||||
|
{
|
||||||
|
|
||||||
|
return {scalar * c.h,
|
||||||
|
scalar * c.s,
|
||||||
|
scalar * c.v};
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ColorHSV operator*(float scalar, const ColorHSV &c)
|
||||||
|
{
|
||||||
|
return {scalar * c.h,
|
||||||
|
scalar * c.s,
|
||||||
|
scalar * c.v};
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ColorHSV operator+(const ColorHSV &c1, const ColorHSV &c2)
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
c1.h + c2.h,
|
||||||
|
c1.s + c2.s,
|
||||||
|
c1.v + c2.v};
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ColorHSV interpolate(const ColorHSV &c1, const ColorHSV &c2, float f)
|
||||||
|
{
|
||||||
|
return ColorHSV{
|
||||||
|
(1.0f - f) * c1.h + f * c2.h,
|
||||||
|
(1.0f - f) * c1.s + f * c2.s,
|
||||||
|
(1.0f - f) * c1.v + f * c2.v};
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef PLATFORM_NATIVE
|
||||||
|
inline void print(const char *prefix, const ColorHSV &c)
|
||||||
|
{
|
||||||
|
Serial.printf("%s HSV(%f, %f, %f)\n", prefix, c.h, c.s, c.v);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
static constexpr int MAX_EFFECT_CONFIG_SIZE = 128;
|
static constexpr int MAX_EFFECT_CONFIG_SIZE = 128;
|
||||||
static constexpr int MAX_EFFECT_CLASS_SIZE = 128;
|
static constexpr int MAX_EFFECT_CLASS_SIZE = 4 * 1024;
|
||||||
|
|
||||||
template <typename TLedStrip>
|
template <typename TLedStrip>
|
||||||
class LedTask
|
class LedTask
|
||||||
|
@ -75,9 +75,10 @@ void _led_task_func(void *params)
|
||||||
|
|
||||||
TLedStrip &ledStrip = *(task->ledStrip_);
|
TLedStrip &ledStrip = *(task->ledStrip_);
|
||||||
// clang-format off
|
// clang-format off
|
||||||
if (dispatchEffectId<EffectId::CIRCULAR >(id, effectFunction, ledStrip, msgBuffer, effectStorage)) { Serial.println("Parsed circular");}
|
if (dispatchEffectId<EffectId::CIRCULAR >(id, effectFunction, ledStrip, msgBuffer, effectStorage)) { Serial.println("Parsed circular");}
|
||||||
else if (dispatchEffectId<EffectId::STATIC >(id, effectFunction, ledStrip, msgBuffer, effectStorage)) { Serial.println("Parsed static");}
|
else if (dispatchEffectId<EffectId::STATIC >(id, effectFunction, ledStrip, msgBuffer, effectStorage)) { Serial.println("Parsed static");}
|
||||||
else if (dispatchEffectId<EffectId::ALEXA_SWIPE>(id, effectFunction, ledStrip, msgBuffer, effectStorage)) { Serial.println("Alexa swipe");}
|
else if (dispatchEffectId<EffectId::ALEXA_SWIPE >(id, effectFunction, ledStrip, msgBuffer, effectStorage)) { Serial.println("Alexa swipe");}
|
||||||
|
else if (dispatchEffectId<EffectId::RANDOM_TWO_COLOR_INTERPOLATION>(id, effectFunction, ledStrip, msgBuffer, effectStorage)) { Serial.println("random color ip");}
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
timeoutMsForEffect = 0;
|
timeoutMsForEffect = 0;
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "effects/Circular.h"
|
#include "effects/Circular.h"
|
||||||
#include "effects/Static.h"
|
#include "effects/Static.h"
|
||||||
#include "effects/AlexaSwipe.h"
|
#include "effects/AlexaSwipe.h"
|
||||||
|
#include "effects/RandomTwoColorInterpolation.h"
|
||||||
|
|
||||||
#include "TaskLed.h"
|
#include "TaskLed.h"
|
||||||
|
|
||||||
|
@ -37,6 +38,9 @@ void tag_handler(uint8_t *sn)
|
||||||
fox = true;
|
fox = true;
|
||||||
//ledTask.startEffect(EffectCircularConfig{2 * 360, 180, ColorRGBW{0, 0, 255, 0}});
|
//ledTask.startEffect(EffectCircularConfig{2 * 360, 180, ColorRGBW{0, 0, 255, 0}});
|
||||||
ledTask.startEffect(EffectAlexaSwipeConfig{20, 30, 3 * 360, 3, 180, true, ColorRGBW{0, 255, 0, 0}, ColorRGBW{0, 0, 255, 0}});
|
ledTask.startEffect(EffectAlexaSwipeConfig{20, 30, 3 * 360, 3, 180, true, ColorRGBW{0, 255, 0, 0}, ColorRGBW{0, 0, 255, 0}});
|
||||||
|
delay(1000);
|
||||||
|
ledTask.startEffect(EffectRandomTwoColorInterpolationConfig{6000, true, 6, rgb2hsv(ColorRGBW{128, 0, 0, 0}),
|
||||||
|
rgb2hsv(ColorRGBW{0, 0, 128, 0}), true, true});
|
||||||
}
|
}
|
||||||
if (sn[4] == 0xf0)
|
if (sn[4] == 0xf0)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue