134 lines
4.0 KiB
C++
134 lines
4.0 KiB
C++
|
|
|
|
#include "fl/stdint.h"
|
|
|
|
#define FASTLED_INTERNAL
|
|
#include "FastLED.h"
|
|
|
|
#include "crgb.h"
|
|
#include "fl/blur.h"
|
|
#include "fl/colorutils_misc.h"
|
|
#include "fl/deprecated.h"
|
|
#include "fl/unused.h"
|
|
#include "fl/xymap.h"
|
|
#include "lib8tion/scale8.h"
|
|
#include "fl/int.h"
|
|
|
|
namespace fl {
|
|
|
|
// Legacy XY function. This is a weak symbol that can be overridden by the user.
|
|
fl::u16 XY(fl::u8 x, fl::u8 y) __attribute__((weak));
|
|
|
|
__attribute__((weak)) fl::u16 XY(fl::u8 x, fl::u8 y) {
|
|
FASTLED_UNUSED(x);
|
|
FASTLED_UNUSED(y);
|
|
FASTLED_ASSERT(false, "the user didn't provide an XY function");
|
|
return 0;
|
|
}
|
|
|
|
// fl::u16 XY(fl::u8 x, fl::u8 y) {
|
|
// return 0;
|
|
// }
|
|
// make this a weak symbol
|
|
namespace {
|
|
fl::u16 xy_legacy_wrapper(fl::u16 x, fl::u16 y, fl::u16 width,
|
|
fl::u16 height) {
|
|
FASTLED_UNUSED(width);
|
|
FASTLED_UNUSED(height);
|
|
return XY(x, y);
|
|
}
|
|
} // namespace
|
|
|
|
// blur1d: one-dimensional blur filter. Spreads light to 2 line neighbors.
|
|
// blur2d: two-dimensional blur filter. Spreads light to 8 XY neighbors.
|
|
//
|
|
// 0 = no spread at all
|
|
// 64 = moderate spreading
|
|
// 172 = maximum smooth, even spreading
|
|
//
|
|
// 173..255 = wider spreading, but increasing flicker
|
|
//
|
|
// Total light is NOT entirely conserved, so many repeated
|
|
// calls to 'blur' will also result in the light fading,
|
|
// eventually all the way to black; this is by design so that
|
|
// it can be used to (slowly) clear the LEDs to black.
|
|
void blur1d(CRGB *leds, fl::u16 numLeds, fract8 blur_amount) {
|
|
fl::u8 keep = 255 - blur_amount;
|
|
fl::u8 seep = blur_amount >> 1;
|
|
CRGB carryover = CRGB::Black;
|
|
for (fl::u16 i = 0; i < numLeds; ++i) {
|
|
CRGB cur = leds[i];
|
|
CRGB part = cur;
|
|
part.nscale8(seep);
|
|
cur.nscale8(keep);
|
|
cur += carryover;
|
|
if (i)
|
|
leds[i - 1] += part;
|
|
leds[i] = cur;
|
|
carryover = part;
|
|
}
|
|
}
|
|
|
|
void blur2d(CRGB *leds, fl::u8 width, fl::u8 height, fract8 blur_amount,
|
|
const XYMap &xymap) {
|
|
blurRows(leds, width, height, blur_amount, xymap);
|
|
blurColumns(leds, width, height, blur_amount, xymap);
|
|
}
|
|
|
|
void blur2d(CRGB *leds, fl::u8 width, fl::u8 height, fract8 blur_amount) {
|
|
XYMap xy =
|
|
XYMap::constructWithUserFunction(width, height, xy_legacy_wrapper);
|
|
blur2d(leds, width, height, blur_amount, xy);
|
|
}
|
|
|
|
void blurRows(CRGB *leds, fl::u8 width, fl::u8 height, fract8 blur_amount,
|
|
const XYMap &xyMap) {
|
|
|
|
/* for( fl::u8 row = 0; row < height; row++) {
|
|
CRGB* rowbase = leds + (row * width);
|
|
blur1d( rowbase, width, blur_amount);
|
|
}
|
|
*/
|
|
// blur rows same as columns, for irregular matrix
|
|
fl::u8 keep = 255 - blur_amount;
|
|
fl::u8 seep = blur_amount >> 1;
|
|
for (fl::u8 row = 0; row < height; row++) {
|
|
CRGB carryover = CRGB::Black;
|
|
for (fl::u8 i = 0; i < width; i++) {
|
|
CRGB cur = leds[xyMap.mapToIndex(i, row)];
|
|
CRGB part = cur;
|
|
part.nscale8(seep);
|
|
cur.nscale8(keep);
|
|
cur += carryover;
|
|
if (i)
|
|
leds[xyMap.mapToIndex(i - 1, row)] += part;
|
|
leds[xyMap.mapToIndex(i, row)] = cur;
|
|
carryover = part;
|
|
}
|
|
}
|
|
}
|
|
|
|
// blurColumns: perform a blur1d on each column of a rectangular matrix
|
|
void blurColumns(CRGB *leds, fl::u8 width, fl::u8 height, fract8 blur_amount,
|
|
const XYMap &xyMap) {
|
|
// blur columns
|
|
fl::u8 keep = 255 - blur_amount;
|
|
fl::u8 seep = blur_amount >> 1;
|
|
for (fl::u8 col = 0; col < width; ++col) {
|
|
CRGB carryover = CRGB::Black;
|
|
for (fl::u8 i = 0; i < height; ++i) {
|
|
CRGB cur = leds[xyMap.mapToIndex(col, i)];
|
|
CRGB part = cur;
|
|
part.nscale8(seep);
|
|
cur.nscale8(keep);
|
|
cur += carryover;
|
|
if (i)
|
|
leds[xyMap.mapToIndex(col, i - 1)] += part;
|
|
leds[xyMap.mapToIndex(col, i)] = cur;
|
|
carryover = part;
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace fl
|