204 lines
7.9 KiB
C++
204 lines
7.9 KiB
C++
/// @file rgbw.h
|
|
/// Functions for red, green, blue, white (RGBW) output
|
|
|
|
#pragma once
|
|
|
|
#include <stdint.h>
|
|
|
|
#include "fl/force_inline.h"
|
|
#include "fl/namespace.h"
|
|
#include "eorder.h"
|
|
|
|
FASTLED_NAMESPACE_BEGIN
|
|
|
|
|
|
enum RGBW_MODE {
|
|
kRGBWInvalid,
|
|
kRGBWNullWhitePixel,
|
|
kRGBWExactColors,
|
|
kRGBWBoostedWhite,
|
|
kRGBWMaxBrightness,
|
|
kRGBWUserFunction
|
|
};
|
|
|
|
enum {
|
|
kRGBWDefaultColorTemp = 6000,
|
|
};
|
|
|
|
struct Rgbw {
|
|
explicit Rgbw(uint16_t white_color_temp = kRGBWDefaultColorTemp,
|
|
RGBW_MODE rgbw_mode = kRGBWExactColors,
|
|
EOrderW _w_placement = WDefault)
|
|
: white_color_temp(white_color_temp), w_placement(_w_placement),
|
|
rgbw_mode(rgbw_mode) {}
|
|
uint16_t white_color_temp = kRGBWDefaultColorTemp;
|
|
EOrderW w_placement = WDefault;
|
|
RGBW_MODE rgbw_mode = kRGBWExactColors;
|
|
FASTLED_FORCE_INLINE bool active() const {
|
|
return rgbw_mode != kRGBWInvalid;
|
|
}
|
|
|
|
static uint32_t size_as_rgb(uint32_t num_of_rgbw_pixels) {
|
|
// The ObjectFLED controller expects the raw pixel byte data in multiples of 3.
|
|
// In the case of src data not a multiple of 3, then we need to
|
|
// add pad bytes so that the delegate controller doesn't walk off the end
|
|
// of the array and invoke a buffer overflow panic.
|
|
num_of_rgbw_pixels = (num_of_rgbw_pixels * 4 + 2) / 3;
|
|
uint32_t extra = num_of_rgbw_pixels % 3 ? 1 : 0;
|
|
num_of_rgbw_pixels += extra;
|
|
return num_of_rgbw_pixels;
|
|
}
|
|
};
|
|
|
|
struct RgbwInvalid : public Rgbw {
|
|
RgbwInvalid() {
|
|
white_color_temp = kRGBWDefaultColorTemp;
|
|
rgbw_mode = kRGBWInvalid;
|
|
}
|
|
static Rgbw value() {
|
|
RgbwInvalid invalid;
|
|
return invalid;
|
|
}
|
|
};
|
|
|
|
struct RgbwDefault : public Rgbw {
|
|
RgbwDefault() {
|
|
white_color_temp = kRGBWDefaultColorTemp;
|
|
rgbw_mode = kRGBWExactColors;
|
|
}
|
|
static Rgbw value() {
|
|
RgbwDefault _default;
|
|
return _default;
|
|
}
|
|
};
|
|
|
|
struct RgbwWhiteIsOff : public Rgbw {
|
|
RgbwWhiteIsOff() {
|
|
white_color_temp = kRGBWDefaultColorTemp;
|
|
rgbw_mode = kRGBWNullWhitePixel;
|
|
}
|
|
static Rgbw value() {
|
|
RgbwWhiteIsOff _default;
|
|
return _default;
|
|
}
|
|
};
|
|
|
|
typedef void (*rgb_2_rgbw_function)(uint16_t w_color_temperature, uint8_t r,
|
|
uint8_t g, uint8_t b, uint8_t r_scale,
|
|
uint8_t g_scale, uint8_t b_scale,
|
|
uint8_t *out_r, uint8_t *out_g,
|
|
uint8_t *out_b, uint8_t *out_w);
|
|
|
|
/// @brief Converts RGB to RGBW using a color transfer method
|
|
/// from saturated color channels to white. This is designed to produce
|
|
/// the most accurate white point for a given color temperature and
|
|
/// reduces power usage of the chip since a white led is much more efficient
|
|
/// than three color channels of the same power mixing together. However
|
|
/// the pixel will never achieve full brightness since the white channel is
|
|
/// 3x more efficient than the color channels mixed together, so in this mode
|
|
/// the max brightness of a given pixel is reduced.
|
|
///
|
|
/// ```
|
|
/// RGB(255, 255, 255) -> RGBW(0, 0, 0, 85)
|
|
/// RGB(255, 0, 0) -> RGBW(255, 0, 0, 0)
|
|
/// ```
|
|
void rgb_2_rgbw_exact(uint16_t w_color_temperature, uint8_t r, uint8_t g,
|
|
uint8_t b, uint8_t r_scale, uint8_t g_scale,
|
|
uint8_t b_scale, uint8_t *out_r, uint8_t *out_g,
|
|
uint8_t *out_b, uint8_t *out_w);
|
|
|
|
/// The minimum brigthness of the RGB channels is used to set the W channel.
|
|
/// This will allow the max brightness of the led chipset to be used. However
|
|
/// the leds will appear over-desaturated in this mode.
|
|
///
|
|
/// ```
|
|
/// RGB(255, 255, 255) -> RGBW(255, 255, 255, 255)
|
|
/// RGB(1, 0, 0) -> RGBW(1, 0, 0, 1)
|
|
/// ```
|
|
void rgb_2_rgbw_max_brightness(uint16_t w_color_temperature, uint8_t r,
|
|
uint8_t g, uint8_t b, uint8_t r_scale,
|
|
uint8_t g_scale, uint8_t b_scale, uint8_t *out_r,
|
|
uint8_t *out_g, uint8_t *out_b, uint8_t *out_w);
|
|
|
|
/// @brief Converts RGB to RGBW with the W channel set to black, always.
|
|
///
|
|
/// ```
|
|
/// RGB(255, 255, 255) -> RGBW(255, 255, 255, 0)
|
|
/// ```
|
|
void rgb_2_rgbw_null_white_pixel(uint16_t w_color_temperature, uint8_t r,
|
|
uint8_t g, uint8_t b, uint8_t r_scale,
|
|
uint8_t g_scale, uint8_t b_scale,
|
|
uint8_t *out_r, uint8_t *out_g, uint8_t *out_b,
|
|
uint8_t *out_w);
|
|
|
|
/// @brief Converts RGB to RGBW with a boosted white channel.
|
|
void rgb_2_rgbw_white_boosted(uint16_t w_color_temperature, uint8_t r,
|
|
uint8_t g, uint8_t b, uint8_t r_scale,
|
|
uint8_t g_scale, uint8_t b_scale, uint8_t *out_r,
|
|
uint8_t *out_g, uint8_t *out_b, uint8_t *out_w);
|
|
|
|
void rgb_2_rgbw_user_function(uint16_t w_color_temperature, uint8_t r,
|
|
uint8_t g, uint8_t b, uint8_t r_scale,
|
|
uint8_t g_scale, uint8_t b_scale, uint8_t *out_r,
|
|
uint8_t *out_g, uint8_t *out_b, uint8_t *out_w);
|
|
|
|
void set_rgb_2_rgbw_function(rgb_2_rgbw_function func);
|
|
|
|
/// @brief Converts RGB to RGBW using one of the functions.
|
|
/// @details Dynamic version of the rgb_w_rgbw function with less chance for
|
|
/// the compiler to optimize.
|
|
FASTLED_FORCE_INLINE void rgb_2_rgbw(
|
|
RGBW_MODE mode, uint16_t w_color_temperature, uint8_t r, uint8_t g,
|
|
uint8_t b, uint8_t r_scale, uint8_t g_scale, uint8_t b_scale,
|
|
uint8_t *out_r, uint8_t *out_g, uint8_t *out_b, uint8_t *out_w) {
|
|
switch (mode) {
|
|
case kRGBWInvalid:
|
|
case kRGBWNullWhitePixel:
|
|
rgb_2_rgbw_null_white_pixel(w_color_temperature, r, g, b, r_scale,
|
|
g_scale, b_scale, out_r, out_g, out_b,
|
|
out_w);
|
|
return;
|
|
case kRGBWExactColors:
|
|
rgb_2_rgbw_exact(w_color_temperature, r, g, b, r_scale, g_scale,
|
|
b_scale, out_r, out_g, out_b, out_w);
|
|
return;
|
|
case kRGBWBoostedWhite:
|
|
rgb_2_rgbw_white_boosted(w_color_temperature, r, g, b, r_scale, g_scale,
|
|
b_scale, out_r, out_g, out_b, out_w);
|
|
return;
|
|
case kRGBWMaxBrightness:
|
|
rgb_2_rgbw_max_brightness(w_color_temperature, r, g, b, r_scale,
|
|
g_scale, b_scale, out_r, out_g, out_b, out_w);
|
|
return;
|
|
case kRGBWUserFunction:
|
|
rgb_2_rgbw_user_function(w_color_temperature, r, g, b, r_scale, g_scale,
|
|
b_scale, out_r, out_g, out_b, out_w);
|
|
return;
|
|
}
|
|
rgb_2_rgbw_null_white_pixel(w_color_temperature, r, g, b, r_scale, g_scale,
|
|
b_scale, out_r, out_g, out_b, out_w);
|
|
}
|
|
|
|
// @brief Converts RGB to RGBW using one of the functions.
|
|
template <RGBW_MODE MODE>
|
|
FASTLED_FORCE_INLINE void
|
|
rgb_2_rgbw(uint16_t w_color_temperature, uint8_t r, uint8_t g, uint8_t b,
|
|
uint8_t r_scale, uint8_t g_scale, uint8_t b_scale, uint8_t *out_r,
|
|
uint8_t *out_g, uint8_t *out_b, uint8_t *out_w) {
|
|
// We trust that the compiler will inline all of this.
|
|
rgb_2_rgbw(MODE, w_color_temperature, r, g, b, r_scale, g_scale, b_scale,
|
|
out_r, out_g, out_b, out_w);
|
|
}
|
|
|
|
// Assuming all RGB pixels are already ordered in native led ordering, then this
|
|
// function will reorder them so that white is also the correct position.
|
|
// b0-b2 are actually rgb that are already in native LED order.
|
|
// and out_b0-out_b3 are the output RGBW in native LED chipset order.
|
|
// w is the white component that needs to be inserted into the RGB data at
|
|
// the correct position.
|
|
void rgbw_partial_reorder(EOrderW w_placement, uint8_t b0, uint8_t b1,
|
|
uint8_t b2, uint8_t w, uint8_t *out_b0,
|
|
uint8_t *out_b1, uint8_t *out_b2, uint8_t *out_b3);
|
|
|
|
|
|
FASTLED_NAMESPACE_END |