Cleaned up repository
- only moving files around
This commit is contained in:
109
esp-firmware/lib/ledtl/Esp32DriverRGBW.cpp
Normal file
109
esp-firmware/lib/ledtl/Esp32DriverRGBW.cpp
Normal file
@@ -0,0 +1,109 @@
|
||||
#ifndef PLATFORM_NATIVE
|
||||
|
||||
#include "drivers/Esp32DriverRGBW.h"
|
||||
|
||||
#include <driver/gpio.h>
|
||||
#include <driver/rmt.h>
|
||||
|
||||
// Timing constants
|
||||
static constexpr uint16_t DIVIDER = 4;
|
||||
static constexpr double RMT_DURATION_NS = 12.5; // Minimum time of a single RMT duration based on clock ns
|
||||
static constexpr uint32_t T0H = 300;
|
||||
static constexpr uint32_t T0L = 900;
|
||||
static constexpr uint32_t T1H = 600;
|
||||
static constexpr uint32_t T1L = 600;
|
||||
static constexpr uint32_t TRS = 80000;
|
||||
static constexpr rmt_item32_t bit0Data = {uint32_t(T0H / (RMT_DURATION_NS * DIVIDER)), 1, uint32_t(T0L / (RMT_DURATION_NS * DIVIDER)), 0};
|
||||
static constexpr rmt_item32_t bit1Data = {uint32_t(T1H / (RMT_DURATION_NS * DIVIDER)), 1, uint32_t(T1L / (RMT_DURATION_NS * DIVIDER)), 0};
|
||||
|
||||
// Function registered at the RMT driver that converts regular uint8_t values containing r,g,b,w values
|
||||
// to rmt_item32_t for each bit. (8 bit -> 32 * 8 bit)
|
||||
static void IRAM_ATTR uint8ToRmtAdaptor(const void *src, rmt_item32_t *dest, size_t srcSize,
|
||||
size_t wantedNum, size_t *translatedSize, size_t *itemNum)
|
||||
{
|
||||
if (src == NULL || dest == NULL)
|
||||
{
|
||||
*translatedSize = 0;
|
||||
*itemNum = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
size_t size = 0;
|
||||
size_t num = 0;
|
||||
uint8_t *psrc = (uint8_t *)src;
|
||||
rmt_item32_t *pdest = dest;
|
||||
while (size < srcSize && num < wantedNum)
|
||||
{
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
// MSB first
|
||||
const bool isBitSet = *psrc & (1 << (7 - i));
|
||||
pdest->val = isBitSet ? bit1Data.val : bit0Data.val;
|
||||
num++;
|
||||
pdest++;
|
||||
}
|
||||
size++;
|
||||
psrc++;
|
||||
}
|
||||
*translatedSize = size;
|
||||
*itemNum = num;
|
||||
}
|
||||
|
||||
void Esp32DriverRGBW::begin(int gpio, int rmtChannel)
|
||||
{
|
||||
rmtChannel_ = rmtChannel;
|
||||
transmitting_ = false;
|
||||
|
||||
rmt_config_t rmt_tx;
|
||||
rmt_tx.channel = static_cast<rmt_channel_t>(rmtChannel);
|
||||
rmt_tx.gpio_num = static_cast<gpio_num_t>(gpio);
|
||||
rmt_tx.rmt_mode = RMT_MODE_TX;
|
||||
rmt_tx.mem_block_num = 1;
|
||||
rmt_tx.clk_div = DIVIDER;
|
||||
rmt_tx.tx_config.loop_en = false;
|
||||
rmt_tx.tx_config.carrier_level = RMT_CARRIER_LEVEL_LOW;
|
||||
rmt_tx.tx_config.carrier_en = false;
|
||||
rmt_tx.tx_config.idle_level = RMT_IDLE_LEVEL_LOW;
|
||||
rmt_tx.tx_config.idle_output_en = true;
|
||||
|
||||
ESP_ERROR_CHECK(rmt_config(&rmt_tx));
|
||||
ESP_ERROR_CHECK(rmt_driver_install(rmt_tx.channel, 0, 0));
|
||||
|
||||
rmt_translator_init((rmt_channel_t)rmtChannel, uint8ToRmtAdaptor);
|
||||
}
|
||||
|
||||
void Esp32DriverRGBW::end()
|
||||
{
|
||||
ESP_ERROR_CHECK(rmt_driver_uninstall((rmt_channel_t)rmtChannel_));
|
||||
}
|
||||
|
||||
void Esp32DriverRGBW::writeSync(const uint32_t *rgbwData, int numLeds)
|
||||
{
|
||||
waitForTransmissionToFinish();
|
||||
auto data = reinterpret_cast<const uint8_t *>(rgbwData);
|
||||
ESP_ERROR_CHECK(rmt_write_sample((rmt_channel_t)rmtChannel_, data, numLeds * 4, true));
|
||||
}
|
||||
|
||||
void Esp32DriverRGBW::writeAsync(const uint32_t *rgbwData, int numLeds)
|
||||
{
|
||||
waitForTransmissionToFinish();
|
||||
auto data = reinterpret_cast<const uint8_t *>(rgbwData);
|
||||
ESP_ERROR_CHECK(rmt_write_sample((rmt_channel_t)rmtChannel_, data, numLeds * 4, false));
|
||||
transmitting_ = true;
|
||||
}
|
||||
|
||||
bool Esp32DriverRGBW::waitForTransmissionToFinish(int waitMs)
|
||||
{
|
||||
if (!transmitting_)
|
||||
return true;
|
||||
auto ret = rmt_wait_tx_done((rmt_channel_t)rmtChannel_, waitMs / portTICK_PERIOD_MS);
|
||||
if (ret == ESP_OK)
|
||||
{
|
||||
transmitting_ = false;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
109
esp-firmware/lib/ledtl/containers/LedStripRGBW.h
Normal file
109
esp-firmware/lib/ledtl/containers/LedStripRGBW.h
Normal file
@@ -0,0 +1,109 @@
|
||||
/// a static array of red-green-blue-white values together with free functions to set them
|
||||
#pragma once
|
||||
|
||||
#include "helpers/ColorRGBW.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
template <int TNumLeds>
|
||||
class LedStripRGBW
|
||||
{
|
||||
public:
|
||||
static constexpr int NUM_LEDS = TNumLeds;
|
||||
|
||||
static constexpr int normalizeIdx(int idx)
|
||||
{
|
||||
return (idx < 0) ? (idx + NUM_LEDS) : (idx >= NUM_LEDS ? idx - NUM_LEDS : idx);
|
||||
}
|
||||
|
||||
void set(int idx, uint8_t r, uint8_t g, uint8_t b, uint8_t w)
|
||||
{
|
||||
// green: 0
|
||||
// red: 8
|
||||
// blue: 16
|
||||
// white: 24
|
||||
idx = normalizeIdx(idx);
|
||||
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_; }
|
||||
constexpr static int numLeds() { return TNumLeds; }
|
||||
|
||||
private:
|
||||
uint32_t data_[TNumLeds];
|
||||
};
|
||||
|
||||
template <typename TLedStrip>
|
||||
constexpr int numLeds()
|
||||
{
|
||||
return TLedStrip::NUM_LEDS;
|
||||
}
|
||||
|
||||
template <int TNumLeds>
|
||||
constexpr int numLeds(const LedStripRGBW<TNumLeds> &)
|
||||
{
|
||||
return TNumLeds;
|
||||
}
|
||||
|
||||
template <int TNumLeds>
|
||||
void setLedRGB(LedStripRGBW<TNumLeds> &s, int beginIdx, int endIdx, uint8_t r, uint8_t g, uint8_t b)
|
||||
{
|
||||
for (int i = beginIdx; i < endIdx; ++i)
|
||||
s.set(i, r, g, b, 0);
|
||||
}
|
||||
|
||||
template <int TNumLeds>
|
||||
void setLedRGB(LedStripRGBW<TNumLeds> &s, int idx, uint8_t r, uint8_t g, uint8_t b)
|
||||
{
|
||||
s.set(idx, r, g, b, 0);
|
||||
}
|
||||
|
||||
template <int TNumLeds>
|
||||
void setLedRGBW(LedStripRGBW<TNumLeds> &s, int beginIdx, int endIdx, uint8_t r, uint8_t g, uint8_t b, uint8_t w)
|
||||
{
|
||||
for (int i = beginIdx; i < endIdx; ++i)
|
||||
s.set(i, r, g, b, w);
|
||||
}
|
||||
|
||||
template <int TNumLeds>
|
||||
void setLedRGBW(LedStripRGBW<TNumLeds> &s, int idx, uint8_t r, uint8_t g, uint8_t b, uint8_t w)
|
||||
{
|
||||
s.set(idx, r, g, b, w);
|
||||
}
|
||||
|
||||
template <int TNumLeds>
|
||||
void setLedRGBW(LedStripRGBW<TNumLeds> &s, int idx, const ColorRGBW &c)
|
||||
{
|
||||
s.set(idx, c.r, c.g, c.b, c.w);
|
||||
}
|
||||
|
||||
template <int TNumLeds>
|
||||
void setLedRGBW(LedStripRGBW<TNumLeds> &s, int beginIdx, int endIdx, const ColorRGBW &c)
|
||||
{
|
||||
for (int i = beginIdx; i < endIdx; ++i)
|
||||
s.set(i, c.r, c.g, c.b, c.w);
|
||||
}
|
||||
|
||||
template <int TNumLeds>
|
||||
void clear(LedStripRGBW<TNumLeds> &s)
|
||||
{
|
||||
for (int i = 0; i < TNumLeds; ++i)
|
||||
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;
|
||||
}
|
||||
23
esp-firmware/lib/ledtl/drivers/Esp32DriverRGBW.h
Normal file
23
esp-firmware/lib/ledtl/drivers/Esp32DriverRGBW.h
Normal file
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef PLATFORM_NATIVE
|
||||
|
||||
#include "containers/LedStripRGBW.h"
|
||||
|
||||
class Esp32DriverRGBW
|
||||
{
|
||||
public:
|
||||
void begin(int gpio, int rmtChannel);
|
||||
void end();
|
||||
|
||||
void writeSync(const uint32_t *rgbwData, int numLeds);
|
||||
|
||||
void writeAsync(const uint32_t *rgbwData, int numLeds);
|
||||
bool waitForTransmissionToFinish(int waitMs = 1000);
|
||||
|
||||
private:
|
||||
int rmtChannel_;
|
||||
bool transmitting_;
|
||||
};
|
||||
|
||||
#endif
|
||||
153
esp-firmware/lib/ledtl/effects/AlexaSwipe.h
Normal file
153
esp-firmware/lib/ledtl/effects/AlexaSwipe.h
Normal file
@@ -0,0 +1,153 @@
|
||||
#pragma once
|
||||
|
||||
#include "effects/Common.h"
|
||||
#include "helpers/ColorRGBW.h"
|
||||
#include "helpers/ColorHSV.h"
|
||||
#include "helpers/ColorConversions.h"
|
||||
#include "helpers/BellCurve.h"
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct EffectAlexaSwipeConfig
|
||||
{
|
||||
float primaryColorWidth; // in degrees
|
||||
float transitionWidth;
|
||||
float swipeSpeed; // in degrees per second
|
||||
float bellCurveWidthInLeds;
|
||||
float startPosition;
|
||||
bool forward;
|
||||
ColorRGBW primaryColor;
|
||||
ColorRGBW secondaryColor;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
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)),
|
||||
finished_(false)
|
||||
{
|
||||
if (cfg.forward)
|
||||
{
|
||||
currentPosition_ = 0;
|
||||
direction_ = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentPosition_ = float(NUM_LEDS) / 2.0f + bellCurveWidth_ / 2;
|
||||
direction_ = -1;
|
||||
}
|
||||
}
|
||||
|
||||
bool finished() const { return finished_; }
|
||||
|
||||
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_;
|
||||
const auto maxPosition = float(NUM_LEDS) / 2.0f + bellCurveWidth_ / 2;
|
||||
const auto minPosition = 0.0f;
|
||||
currentPosition_ = std::min(currentPosition_, maxPosition);
|
||||
currentPosition_ = std::max(currentPosition_, minPosition);
|
||||
if (currentPosition_ <= minPosition || currentPosition_ >= maxPosition)
|
||||
finished_ = true;
|
||||
|
||||
return DELAY_MS;
|
||||
}
|
||||
|
||||
private:
|
||||
void getParams(float x, float &interpFac, float &brightness)
|
||||
{
|
||||
brightness = stepFunction(x, bellCurveWidth_, invBellCurveWidth_);
|
||||
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_;
|
||||
|
||||
bool finished_;
|
||||
};
|
||||
|
||||
// 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>;
|
||||
};
|
||||
90
esp-firmware/lib/ledtl/effects/Circular.h
Normal file
90
esp-firmware/lib/ledtl/effects/Circular.h
Normal file
@@ -0,0 +1,90 @@
|
||||
#pragma once
|
||||
|
||||
#include "effects/Common.h"
|
||||
#include "helpers/ColorRGBW.h"
|
||||
#include "helpers/BellCurve.h"
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct EffectCircularConfig
|
||||
{
|
||||
float speed; // in degrees per second
|
||||
float width; // width in degrees
|
||||
ColorRGBW color;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
template <typename TLedStrip>
|
||||
class EffectCircular
|
||||
{
|
||||
public:
|
||||
static constexpr auto NUM_LEDS = numLeds<TLedStrip>();
|
||||
static constexpr int DELAY_MS = 10;
|
||||
using ConfigType = EffectCircularConfig;
|
||||
|
||||
EffectCircular(const EffectCircularConfig &cfg, TLedStrip &ledStrip)
|
||||
: config_(cfg),
|
||||
ledStrip_(ledStrip),
|
||||
currentPosition_(0),
|
||||
widthInLeds_((numLeds(ledStrip) * cfg.width / 360)),
|
||||
invWidth_(1.0f / widthInLeds_)
|
||||
{
|
||||
}
|
||||
|
||||
int operator()()
|
||||
{
|
||||
int startLed = int(currentPosition_);
|
||||
float distDown = currentPosition_ - float(startLed);
|
||||
float distUp = 1.f - distDown;
|
||||
|
||||
clear(ledStrip_);
|
||||
// center
|
||||
setLedRGBW(ledStrip_, startLed,
|
||||
config_.color * bellCurveApproximation(distDown, invWidth_));
|
||||
|
||||
// down
|
||||
for (int i = 1; i < widthInLeds_ / 2 + 1; ++i)
|
||||
{
|
||||
setLedRGBW(ledStrip_, startLed - i,
|
||||
config_.color * bellCurveApproximation(distDown + i, invWidth_));
|
||||
}
|
||||
|
||||
// up
|
||||
for (int i = 1; i < widthInLeds_ / 2 + 1; ++i)
|
||||
{
|
||||
setLedRGBW(ledStrip_, startLed + i,
|
||||
config_.color * bellCurveApproximation(distUp + i - 1, invWidth_));
|
||||
}
|
||||
|
||||
currentPosition_ += config_.speed / 1000 / 360 * NUM_LEDS * DELAY_MS;
|
||||
if (currentPosition_ > NUM_LEDS)
|
||||
currentPosition_ -= NUM_LEDS;
|
||||
|
||||
return DELAY_MS;
|
||||
}
|
||||
|
||||
private:
|
||||
EffectCircularConfig config_;
|
||||
TLedStrip &ledStrip_;
|
||||
float currentPosition_; // between 0 and num leds
|
||||
int widthInLeds_;
|
||||
float invWidth_;
|
||||
};
|
||||
|
||||
// Traits
|
||||
template <>
|
||||
struct EffectIdToConfig<EffectId::CIRCULAR>
|
||||
{
|
||||
using type = EffectCircularConfig;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct EffectConfigToId<EffectCircularConfig>
|
||||
{
|
||||
static constexpr auto id = EffectId::CIRCULAR;
|
||||
};
|
||||
|
||||
template <typename TLedStrip>
|
||||
struct EffectIdToClass<EffectId::CIRCULAR, TLedStrip>
|
||||
{
|
||||
using type = EffectCircular<TLedStrip>;
|
||||
};
|
||||
27
esp-firmware/lib/ledtl/effects/Common.h
Normal file
27
esp-firmware/lib/ledtl/effects/Common.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
enum class EffectId
|
||||
{
|
||||
STATIC,
|
||||
CIRCULAR,
|
||||
ALEXA_SWIPE,
|
||||
RANDOM_TWO_COLOR_INTERPOLATION,
|
||||
SWIPE_AND_CHANGE, // combination of ALEXA_SWIPE and RANDOM_TWO_COLOR_INTERPOLATION
|
||||
REVERSE_SWIPE,
|
||||
STATIC_DETAILED,
|
||||
};
|
||||
|
||||
template <EffectId id>
|
||||
struct EffectIdToConfig
|
||||
{
|
||||
};
|
||||
|
||||
template <typename EffectConfig>
|
||||
struct EffectConfigToId
|
||||
{
|
||||
};
|
||||
|
||||
template <EffectId id, typename TLedStrip>
|
||||
struct EffectIdToClass
|
||||
{
|
||||
};
|
||||
155
esp-firmware/lib/ledtl/effects/RandomTwoColorInterpolation.h
Normal file
155
esp-firmware/lib/ledtl/effects/RandomTwoColorInterpolation.h
Normal file
@@ -0,0 +1,155 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "effects/Common.h"
|
||||
#include "helpers/ColorRGBW.h"
|
||||
#include "helpers/ColorHSV.h"
|
||||
#include "helpers/ColorConversions.h"
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct EffectRandomTwoColorInterpolationConfig
|
||||
{
|
||||
int32_t cycleDurationMs;
|
||||
bool startWithExisting;
|
||||
int32_t numSegments;
|
||||
|
||||
bool hue1Random;
|
||||
bool hue2Random;
|
||||
|
||||
ColorHSV color1;
|
||||
ColorHSV color2;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
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_);
|
||||
}
|
||||
|
||||
void begin()
|
||||
{
|
||||
if (config_.startWithExisting)
|
||||
for (int i = 0; i < NUM_LEDS; ++i)
|
||||
currentColors_[i] = rgb2hsv(getLedRGBW(ledStrip_, i));
|
||||
}
|
||||
|
||||
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>;
|
||||
};
|
||||
112
esp-firmware/lib/ledtl/effects/ReverseSwipe.h
Normal file
112
esp-firmware/lib/ledtl/effects/ReverseSwipe.h
Normal file
@@ -0,0 +1,112 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "effects/Common.h"
|
||||
#include "helpers/BellCurve.h"
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct EffectReverseSwipeConfig
|
||||
{
|
||||
float swipeSpeed; // in degrees per second
|
||||
float bellCurveWidthInLeds;
|
||||
float startPosition;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
template <typename TLedStrip>
|
||||
class EffectReverseSwipe
|
||||
{
|
||||
|
||||
public:
|
||||
static constexpr auto NUM_LEDS = numLeds<TLedStrip>();
|
||||
static constexpr int DELAY_MS = 10;
|
||||
|
||||
using ConfigType = EffectReverseSwipeConfig;
|
||||
|
||||
EffectReverseSwipe(const EffectReverseSwipeConfig &cfg, TLedStrip &ledStrip)
|
||||
: ledStrip_(ledStrip),
|
||||
currentPosition_(float(NUM_LEDS) / 2 + 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),
|
||||
finished_(false)
|
||||
{
|
||||
for (int i = 0; i < NUM_LEDS; ++i)
|
||||
state_[i] = getLedRGBW(ledStrip_, i);
|
||||
}
|
||||
|
||||
bool finished() const { return finished_; }
|
||||
|
||||
int operator()()
|
||||
{
|
||||
if (finished_)
|
||||
return 60000;
|
||||
|
||||
const auto width = std::min(int(currentPosition_ + 1), int(NUM_LEDS / 2) + 1);
|
||||
|
||||
{
|
||||
float brightness = stepFunction(currentPosition_, bellCurveWidth_, invBellCurveWidth_);
|
||||
ColorRGBW &prevC = state_[ledStrip_.normalizeIdx(startPosition_)];
|
||||
setLedRGBW(ledStrip_, startPosition_, prevC * brightness);
|
||||
}
|
||||
|
||||
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;
|
||||
float brightness = stepFunction(x, bellCurveWidth_, invBellCurveWidth_);
|
||||
ColorRGBW &prevC1 = state_[ledStrip_.normalizeIdx(led1)];
|
||||
ColorRGBW &prevC2 = state_[ledStrip_.normalizeIdx(led2)];
|
||||
|
||||
setLedRGBW(ledStrip_, led1, prevC1 * brightness);
|
||||
setLedRGBW(ledStrip_, led2, prevC2 * brightness);
|
||||
}
|
||||
}
|
||||
|
||||
currentPosition_ -= speed_;
|
||||
if (currentPosition_ < 0)
|
||||
{
|
||||
finished_ = true;
|
||||
clear(ledStrip_);
|
||||
}
|
||||
|
||||
return DELAY_MS;
|
||||
}
|
||||
|
||||
private:
|
||||
TLedStrip &ledStrip_;
|
||||
float currentPosition_;
|
||||
|
||||
float bellCurveWidth_;
|
||||
float invBellCurveWidth_;
|
||||
float speed_;
|
||||
|
||||
int startPosition_;
|
||||
|
||||
bool finished_;
|
||||
|
||||
ColorRGBW state_[NUM_LEDS];
|
||||
};
|
||||
|
||||
// Traits
|
||||
template <>
|
||||
struct EffectIdToConfig<EffectId::REVERSE_SWIPE>
|
||||
{
|
||||
using type = EffectReverseSwipeConfig;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct EffectConfigToId<EffectReverseSwipeConfig>
|
||||
{
|
||||
static constexpr auto id = EffectId::REVERSE_SWIPE;
|
||||
};
|
||||
|
||||
template <typename TLedStrip>
|
||||
struct EffectIdToClass<EffectId::REVERSE_SWIPE, TLedStrip>
|
||||
{
|
||||
using type = EffectReverseSwipe<TLedStrip>;
|
||||
};
|
||||
63
esp-firmware/lib/ledtl/effects/Static.h
Normal file
63
esp-firmware/lib/ledtl/effects/Static.h
Normal file
@@ -0,0 +1,63 @@
|
||||
#pragma once
|
||||
|
||||
#include "effects/Common.h"
|
||||
#include "helpers/ColorRGBW.h"
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct EffectStaticConfig
|
||||
{
|
||||
EffectStaticConfig(const ColorRGBW &c = ColorRGBW{0, 0, 0, 0}, uint16_t beg = 0, uint16_t en = 0)
|
||||
: color(c), begin(beg), end(en) {}
|
||||
|
||||
ColorRGBW color;
|
||||
uint16_t begin = 0;
|
||||
uint16_t end = 0;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
template <typename TLedStrip>
|
||||
class EffectStatic
|
||||
{
|
||||
public:
|
||||
static constexpr auto NUM_LEDS = numLeds<TLedStrip>();
|
||||
using ConfigType = EffectStaticConfig;
|
||||
|
||||
EffectStatic(const EffectStaticConfig &cfg, TLedStrip &ledStrip)
|
||||
: config_(cfg),
|
||||
ledStrip_(ledStrip)
|
||||
{
|
||||
}
|
||||
|
||||
int operator()()
|
||||
{
|
||||
if (config_.begin == config_.end)
|
||||
setLedRGBW(ledStrip_, 0, NUM_LEDS, config_.color);
|
||||
else
|
||||
setLedRGBW(ledStrip_, config_.begin, config_.end, config_.color);
|
||||
|
||||
return 10000; // nothing changing, return some large time to sleep
|
||||
}
|
||||
|
||||
private:
|
||||
EffectStaticConfig config_;
|
||||
TLedStrip &ledStrip_;
|
||||
};
|
||||
|
||||
// Traits
|
||||
template <>
|
||||
struct EffectIdToConfig<EffectId::STATIC>
|
||||
{
|
||||
using type = EffectStaticConfig;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct EffectConfigToId<EffectStaticConfig>
|
||||
{
|
||||
static constexpr auto id = EffectId::STATIC;
|
||||
};
|
||||
|
||||
template <typename TLedStrip>
|
||||
struct EffectIdToClass<EffectId::STATIC, TLedStrip>
|
||||
{
|
||||
using type = EffectStatic<TLedStrip>;
|
||||
};
|
||||
107
esp-firmware/lib/ledtl/effects/StaticDetailed.h
Normal file
107
esp-firmware/lib/ledtl/effects/StaticDetailed.h
Normal file
@@ -0,0 +1,107 @@
|
||||
#pragma once
|
||||
|
||||
#include "effects/Common.h"
|
||||
#include "helpers/ColorRGBW.h"
|
||||
#include "helpers/ColorConversions.h"
|
||||
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct EffectStaticDetailedConfig
|
||||
{
|
||||
EffectStaticDetailedConfig(const ColorRGBW &c = ColorRGBW{0, 0, 0, 0}, uint16_t beg = 0, uint16_t en = 0)
|
||||
: color(c), begin(beg), end(en) {}
|
||||
|
||||
ColorRGBW color;
|
||||
uint16_t increment = 1;
|
||||
float begin = 0.0f;
|
||||
float end = 0.0f;
|
||||
float transition_time_in_ms = 0.0f;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
template <typename TLedStrip>
|
||||
class EffectStaticDetailed
|
||||
{
|
||||
public:
|
||||
static constexpr auto NUM_LEDS = numLeds<TLedStrip>();
|
||||
static constexpr int DELAY_MS = 10;
|
||||
using ConfigType = EffectStaticDetailedConfig;
|
||||
|
||||
EffectStaticDetailed(const EffectStaticDetailedConfig &cfg, TLedStrip &ledStrip)
|
||||
: config_(cfg),
|
||||
ledStrip_(ledStrip)
|
||||
{
|
||||
for (int i = 0; i < NUM_LEDS; ++i)
|
||||
state_[i] = getLedRGBW(ledStrip_, i);
|
||||
|
||||
beginIdx_ = constrain(static_cast<int>(cfg.begin * NUM_LEDS + 0.5f), 0, NUM_LEDS - 1);
|
||||
endIdx_ = constrain(static_cast<int>(cfg.end * NUM_LEDS + 0.5f), 0, NUM_LEDS - 1);
|
||||
while (endIdx_ < beginIdx_)
|
||||
endIdx_ += NUM_LEDS;
|
||||
}
|
||||
|
||||
bool finished() const { return finished_; }
|
||||
|
||||
int operator()()
|
||||
{
|
||||
if (finished_)
|
||||
return 1000000;
|
||||
|
||||
const float progress = config_.transition_time_in_ms > 0.0f ? static_cast<float>(DELAY_MS * calls_) / config_.transition_time_in_ms : 1.f;
|
||||
|
||||
// Finished case
|
||||
if (config_.transition_time_in_ms <= 0.0f || progress >= 1.0)
|
||||
{
|
||||
finished_ = true;
|
||||
clear(ledStrip_);
|
||||
for (int i = beginIdx_; i < endIdx_; i += config_.increment)
|
||||
setLedRGBW(ledStrip_, i % NUM_LEDS, config_.color);
|
||||
return 10000000;
|
||||
}
|
||||
|
||||
// In-progress case
|
||||
clear(ledStrip_);
|
||||
for (int i = beginIdx_; i < endIdx_; i += config_.increment)
|
||||
{
|
||||
const auto idx = i % NUM_LEDS;
|
||||
ColorRGBW newColor = ColorRGBW::interpolate(state_[idx], config_.color, progress);
|
||||
setLedRGBW(ledStrip_, idx, newColor);
|
||||
}
|
||||
|
||||
++calls_;
|
||||
return DELAY_MS;
|
||||
}
|
||||
|
||||
private:
|
||||
static int int_interpolate(int prev, int next, float progress)
|
||||
{
|
||||
return static_cast<float>(prev) * (1 - progress) +
|
||||
static_cast<float>(next) * progress;
|
||||
}
|
||||
EffectStaticDetailedConfig config_;
|
||||
TLedStrip &ledStrip_;
|
||||
ColorRGBW state_[NUM_LEDS];
|
||||
int beginIdx_;
|
||||
int endIdx_;
|
||||
int calls_ = 0;
|
||||
bool finished_ = false;
|
||||
};
|
||||
|
||||
// Traits
|
||||
template <>
|
||||
struct EffectIdToConfig<EffectId::STATIC_DETAILED>
|
||||
{
|
||||
using type = EffectStaticDetailedConfig;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct EffectConfigToId<EffectStaticDetailedConfig>
|
||||
{
|
||||
static constexpr auto id = EffectId::STATIC_DETAILED;
|
||||
};
|
||||
|
||||
template <typename TLedStrip>
|
||||
struct EffectIdToClass<EffectId::STATIC_DETAILED, TLedStrip>
|
||||
{
|
||||
using type = EffectStaticDetailed<TLedStrip>;
|
||||
};
|
||||
64
esp-firmware/lib/ledtl/effects/SwipeAndChange.h
Normal file
64
esp-firmware/lib/ledtl/effects/SwipeAndChange.h
Normal file
@@ -0,0 +1,64 @@
|
||||
#pragma once
|
||||
|
||||
#include "effects/Common.h"
|
||||
#include "effects/AlexaSwipe.h"
|
||||
#include "effects/RandomTwoColorInterpolation.h"
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct EffectSwipeAndChangeConfig
|
||||
{
|
||||
EffectAlexaSwipeConfig swipeCfg;
|
||||
EffectRandomTwoColorInterpolationConfig changeCfg;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
template <typename TLedStrip>
|
||||
class EffectSwipeAndChange
|
||||
{
|
||||
public:
|
||||
EffectSwipeAndChange(const EffectSwipeAndChangeConfig &cfg, TLedStrip &ledStrip)
|
||||
: effect1_(cfg.swipeCfg, ledStrip),
|
||||
effect2_(cfg.changeCfg, ledStrip),
|
||||
effectRunning_(0)
|
||||
{
|
||||
}
|
||||
|
||||
int operator()()
|
||||
{
|
||||
if (!effect1_.finished())
|
||||
{
|
||||
return effect1_();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (effectRunning_ == 0)
|
||||
effect2_.begin();
|
||||
effectRunning_ = 1;
|
||||
return effect2_();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
EffectAlexaSwipe<TLedStrip> effect1_;
|
||||
EffectRandomTwoColorInterpolation<TLedStrip> effect2_;
|
||||
int effectRunning_;
|
||||
};
|
||||
|
||||
// Traits
|
||||
template <>
|
||||
struct EffectIdToConfig<EffectId::SWIPE_AND_CHANGE>
|
||||
{
|
||||
using type = EffectSwipeAndChangeConfig;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct EffectConfigToId<EffectSwipeAndChangeConfig>
|
||||
{
|
||||
static constexpr auto id = EffectId::SWIPE_AND_CHANGE;
|
||||
};
|
||||
|
||||
template <typename TLedStrip>
|
||||
struct EffectIdToClass<EffectId::SWIPE_AND_CHANGE, TLedStrip>
|
||||
{
|
||||
using type = EffectSwipeAndChange<TLedStrip>;
|
||||
};
|
||||
6
esp-firmware/lib/ledtl/effects/swipe.py
Normal file
6
esp-firmware/lib/ledtl/effects/swipe.py
Normal file
File diff suppressed because one or more lines are too long
35
esp-firmware/lib/ledtl/helpers/BellCurve.h
Normal file
35
esp-firmware/lib/ledtl/helpers/BellCurve.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
static inline float bellCurveApproximation(float x, float inverseWidth)
|
||||
{
|
||||
if (x < 0)
|
||||
x = -x;
|
||||
|
||||
const auto nx = x * inverseWidth * 4;
|
||||
if (nx > 2)
|
||||
return 0.0f;
|
||||
|
||||
const auto x2 = nx * nx;
|
||||
const auto x3 = x2 * nx;
|
||||
const auto res = 1.0f + 0.27606958941084f * x3 - 0.80213917882168f * x2;
|
||||
|
||||
return res < 0.0f ? 0.0f : res;
|
||||
}
|
||||
|
||||
// Function start at 0 (x=0) and goes smoothly up to 1 and arrives 1 at x=width
|
||||
// inverse width has to be 1 / width (should be cached outside)
|
||||
static inline float stepFunction(float x, float width, float inverseWidth)
|
||||
{
|
||||
if (x < 0.0f)
|
||||
return 0.0f;
|
||||
if (x >= width)
|
||||
return 1.0f;
|
||||
|
||||
auto bellInvWidth = inverseWidth * 0.5f;
|
||||
auto nx = (-x + width) * bellInvWidth * 4;
|
||||
auto x2 = nx * nx;
|
||||
auto x3 = x2 * nx;
|
||||
return 1 + 0.2760695894 * x3 - 0.8021391 * x2;
|
||||
}
|
||||
116
esp-firmware/lib/ledtl/helpers/ColorConversions.h
Normal file
116
esp-firmware/lib/ledtl/helpers/ColorConversions.h
Normal file
@@ -0,0 +1,116 @@
|
||||
#pragma once
|
||||
|
||||
#include "helpers/ColorHSV.h"
|
||||
#include "helpers/ColorRGBW.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
|
||||
// https://stackoverflow.com/questions/3018313/algorithm-to-convert-rgb-to-hsv-and-hsv-to-rgb-in-range-0-255-for-both
|
||||
inline ColorHSV rgb2hsv(const ColorRGBW &in)
|
||||
{
|
||||
ColorHSV out;
|
||||
|
||||
const float r = (float)(in.r) / 255.0f;
|
||||
const float g = (float)(in.g) / 255.0f;
|
||||
const float b = (float)(in.b) / 255.0f;
|
||||
|
||||
const float min = std::min(r, std::min(g, b));
|
||||
const float max = std::max(r, std::max(g, b));
|
||||
|
||||
out.v = max; // v
|
||||
const float delta = max - min;
|
||||
if (delta < 0.00001f)
|
||||
{
|
||||
out.s = 0;
|
||||
out.h = 0; // undefined, maybe nan?
|
||||
return out;
|
||||
}
|
||||
if (max > 0.0f)
|
||||
{ // NOTE: if Max is == 0, this divide would cause a crash
|
||||
out.s = (delta / max); // s
|
||||
}
|
||||
else
|
||||
{
|
||||
// if max is 0, then r = g = b = 0
|
||||
// s = 0, h is undefined
|
||||
out.s = 0.0f;
|
||||
out.h = 0.0f; //NAN; // its now undefined
|
||||
return out;
|
||||
}
|
||||
if (r >= max) // > is bogus, just keeps compiler happy
|
||||
out.h = (g - b) / delta; // between yellow & magenta
|
||||
else if (g >= max)
|
||||
out.h = 2.0f + (b - r) / delta; // between cyan & yellow
|
||||
else
|
||||
out.h = 4.0f + (r - g) / delta; // between magenta & cyan
|
||||
|
||||
out.h *= 60.0f; // degrees
|
||||
|
||||
if (out.h < 0.0f)
|
||||
out.h += 360.0f;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
ColorRGBW hsv2rgb(const ColorHSV &in)
|
||||
{
|
||||
int i;
|
||||
ColorRGBW out;
|
||||
out.w = 0;
|
||||
|
||||
if (in.s <= 0.0f)
|
||||
{ // < is bogus, just shuts up warnings
|
||||
out.r = (uint8_t)(in.v * 255.0f);
|
||||
out.g = (uint8_t)(in.v * 255.0f);
|
||||
out.b = (uint8_t)(in.v * 255.0f);
|
||||
return out;
|
||||
}
|
||||
float hh = in.h;
|
||||
if (hh >= 360.0f)
|
||||
hh = 0.0f;
|
||||
hh /= 60.0f;
|
||||
i = (long)hh;
|
||||
auto ff = hh - i;
|
||||
float p = in.v * (1.0f - in.s);
|
||||
float q = in.v * (1.0f - (in.s * ff));
|
||||
float t = in.v * (1.0f - (in.s * (1.0f - ff)));
|
||||
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
out.r = (uint8_t)(in.v * 255.0f);
|
||||
out.g = (uint8_t)(t * 255.0f);
|
||||
out.b = (uint8_t)(p * 255.0f);
|
||||
break;
|
||||
case 1:
|
||||
out.r = (uint8_t)(q * 255.0f);
|
||||
out.g = (uint8_t)(in.v * 255.0f);
|
||||
out.b = (uint8_t)(p * 255.0f);
|
||||
break;
|
||||
case 2:
|
||||
out.r = (uint8_t)(p * 255.0f);
|
||||
out.g = (uint8_t)(in.v * 255.0f);
|
||||
out.b = (uint8_t)(t * 255.0f);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
out.r = (uint8_t)(p * 255.0f);
|
||||
out.g = (uint8_t)(q * 255.0f);
|
||||
out.b = (uint8_t)(in.v * 255.0f);
|
||||
break;
|
||||
case 4:
|
||||
out.r = (uint8_t)(t * 255.0f);
|
||||
out.g = (uint8_t)(p * 255.0f);
|
||||
out.b = (uint8_t)(in.v * 255.0f);
|
||||
break;
|
||||
case 5:
|
||||
default:
|
||||
out.r = (uint8_t)(in.v * 255.0f);
|
||||
out.g = (uint8_t)(p * 255.0f);
|
||||
out.b = (uint8_t)(q * 255.0f);
|
||||
break;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
46
esp-firmware/lib/ledtl/helpers/ColorHSV.h
Normal file
46
esp-firmware/lib/ledtl/helpers/ColorHSV.h
Normal file
@@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
struct ColorHSV
|
||||
{
|
||||
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
|
||||
26
esp-firmware/lib/ledtl/helpers/ColorRGBW.h
Normal file
26
esp-firmware/lib/ledtl/helpers/ColorRGBW.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
struct ColorRGBW
|
||||
{
|
||||
uint8_t r, g, b, w;
|
||||
|
||||
ColorRGBW operator*(float s) const
|
||||
{
|
||||
return {uint8_t(s * r),
|
||||
uint8_t(s * g),
|
||||
uint8_t(s * b),
|
||||
uint8_t(s * w)};
|
||||
}
|
||||
|
||||
static inline ColorRGBW interpolate(const ColorRGBW &c1, const ColorRGBW &c2, float f)
|
||||
{
|
||||
return ColorRGBW{
|
||||
static_cast<uint8_t>((1.0f - f) * static_cast<float>(c1.r) + f * static_cast<float>(c2.r)),
|
||||
static_cast<uint8_t>((1.0f - f) * static_cast<float>(c1.g) + f * static_cast<float>(c2.g)),
|
||||
static_cast<uint8_t>((1.0f - f) * static_cast<float>(c1.b) + f * static_cast<float>(c2.b)),
|
||||
static_cast<uint8_t>((1.0f - f) * static_cast<float>(c1.w) + f * static_cast<float>(c2.w)),
|
||||
};
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user