FastLED 3.10.8
Loading...
Searching...
No Matches
luminova.cpp.hpp
Go to the documentation of this file.
1#ifndef FASTLED_INTERNAL
2#define FASTLED_INTERNAL
3#endif
4
5#include "fl/fx/2d/luminova.h"
6
7// Includes needed for implementation
8#include "fl/system/fastled.h"
9#include "fl/gfx/blur.h"
10#include "fl/math/math.h"
11#include "fl/math/math.h"
12#include "fl/math/xymap.h"
13#include "fl/stl/vector.h"
14#include "crgb.h"
15#include "noise.h"
16#include "fl/stl/noexcept.h"
17
18namespace fl {
19
20Luminova::Luminova(const XYMap &xyMap, const Params &params)
21 FL_NO_EXCEPT : Fx2d(xyMap), mParams(params) {
22 int cap = params.max_particles;
23 if (cap <= 0) {
24 cap = 1;
25 }
26 mParticles.resize(static_cast<size_t>(cap));
27 // Initialize as dead
28 for (size_t i = 0; i < mParticles.size(); ++i) {
29 mParticles[i].alive = false;
30 }
31}
32
33void Luminova::setMaxParticles(int max_particles) FL_NO_EXCEPT {
34 if (max_particles <= 0) {
35 max_particles = 1;
36 }
37 if (static_cast<int>(mParticles.size()) == max_particles) {
38 return;
39 }
40 mParticles.clear();
41 mParticles.resize(static_cast<size_t>(max_particles));
42 for (size_t i = 0; i < mParticles.size(); ++i) {
43 mParticles[i].alive = false;
44 }
45}
46
48 // Position at center
49 const float cx = static_cast<float>(getWidth() - 1) * 0.5f;
50 const float cy = static_cast<float>(getHeight() - 1) * 0.5f;
51 p.x = cx;
52 p.y = cy;
53
54 // Original used noise(I)*W, we approximate with 1D noise scaled to width
55 int I = static_cast<int>(tt / 50);
56 u8 n1 = inoise8(static_cast<u16>(I * 19));
57 float noiseW = (static_cast<float>(n1) / 255.0f) * static_cast<float>(getWidth());
58
59 p.a = static_cast<float>(tt) * 1.25f + noiseW;
60 p.f = (tt & 1u) ? +1 : -1;
61 p.g = I;
62 p.s = 3.0f;
63 p.alive = true;
64}
65
67 if (!mXyMap.has(x, y)) {
68 return;
69 }
70 const u16 idx = mXyMap.mapToIndex(static_cast<u16>(x), static_cast<u16>(y));
71 leds[idx] += CHSV(0, 0, scale8(v, mParams.point_gain));
72}
73
74void Luminova::plotSoftDot(fl::span<CRGB> leds, float fx, float fy, float s) const FL_NO_EXCEPT {
75 // Map s (decays from ~3) to a pixel radius 1..3
76 float r = fl::clamp<float>(s * 0.5f, 1.0f, 3.0f);
77 int R = static_cast<int>(fl::ceil(r));
78 // Avoid roundf() to prevent AVR macro conflicts; do manual symmetric rounding
79 int cx = static_cast<int>(fx + (fx >= 0.0f ? 0.5f : -0.5f));
80 int cy = static_cast<int>(fy + (fy >= 0.0f ? 0.5f : -0.5f));
81 float r2 = r * r;
82 for (int dy = -R; dy <= R; ++dy) {
83 for (int dx = -R; dx <= R; ++dx) {
84 float d2 = static_cast<float>(dx * dx + dy * dy);
85 if (d2 <= r2) {
86 float fall = 1.0f - (d2 / (r2 + 0.0001f));
87 float vf = 255.0f * fall;
88 if (vf < 0.0f) vf = 0.0f;
89 if (vf > 255.0f) vf = 255.0f;
90 u8 v = static_cast<u8>(vf);
91 plotDot(leds, cx + dx, cy + dy, v);
92 }
93 }
94 }
95}
96
98 // Fade + blur trails each frame
99 fadeToBlackBy(context.leds, mParams.fade_amount);
100 blur2d(context.leds, static_cast<fl::u8>(getWidth()), static_cast<fl::u8>(getHeight()),
101 mParams.blur_amount, mXyMap);
102
103 // Spawn/overwrite one particle per frame, round-robin across pool
104 if (!mParticles.empty()) {
105 size_t idx = static_cast<size_t>(mTick % static_cast<fl::u32>(mParticles.size()));
107 }
108
109 // Update and draw all particles
110 for (size_t i = 0; i < mParticles.size(); ++i) {
111 Particle &p = mParticles[i];
112 if (!p.alive) {
113 continue;
114 }
115
116 // s *= 0.997
117 p.s *= 0.997f;
118 if (p.s < 0.5f) {
119 p.alive = false;
120 continue;
121 }
122
123 // angle jitter using 2D noise: (t/99, g)
124 float tOver99 = static_cast<float>(mTick) / 99.0f;
125 u8 n2 = inoise8(static_cast<u16>(tOver99 * 4096.0f), static_cast<u16>(p.g * 37));
126 float n2c = (static_cast<int>(n2) - 128) / 255.0f; // ~ -0.5 .. +0.5
127 p.a += (n2c) / 9.0f;
128
129 float aa = p.a * static_cast<float>(p.f);
130 p.x += fl::cosf(aa);
131 p.y += fl::sinf(aa);
132
133 plotSoftDot(context.leds, p.x, p.y, p.s);
134 }
135
136 ++mTick;
137}
138
139} // namespace fl
CRGB leds[1]
XYMap mXyMap
Definition fx2d.h:31
u16 xyMap(u16 x, u16 y) const FL_NO_EXCEPT
Definition fx2d.h:21
u16 getWidth() const FL_NO_EXCEPT
Definition fx2d.h:25
Fx2d(const XYMap &xyMap) FL_NO_EXCEPT
Definition fx2d.h:20
u16 getHeight() const FL_NO_EXCEPT
Definition fx2d.h:24
fl::u32 mTick
Definition luminova.h:60
Luminova(const XYMap &xyMap, const Params &params=Params()) FL_NO_EXCEPT
LuminovaParams Params
Definition luminova.h:29
void draw(DrawContext context) FL_NO_EXCEPT override
void resetParticle(Particle &p, fl::u32 tick) FL_NO_EXCEPT
Params mParams
Definition luminova.h:59
void plotSoftDot(fl::span< CRGB > leds, float fx, float fy, float s) const FL_NO_EXCEPT
fl::vector< Particle > mParticles
Definition luminova.h:61
void plotDot(fl::span< CRGB > leds, int x, int y, u8 v) const FL_NO_EXCEPT
void setMaxParticles(int max_particles) FL_NO_EXCEPT
void plotSoftDot(float fx, float fy, float s)
Definition Luminova.h:85
void plotDot(int x, int y, uint8_t v)
Definition Luminova.h:77
void resetParticle(P &p, uint32_t tt)
Definition Luminova.h:59
Internal FastLED header for implementation files.
fl::hsv8 CHSV
Definition chsv.h:11
fl::u8 inoise8(fl::u16 x, fl::u16 y, fl::u16 z) FL_NO_EXCEPT
unsigned char u8
Definition s16x16x4.h:132
unsigned char u8
Definition stdint.h:131
u8 u8 fract8 blur_amount FL_NO_EXCEPT
Definition blur.h:186
void blur2d(fl::span< CRGB > leds, u8 width, u8 height, fract8 blur_amount, const XYMap &xymap) FL_NO_EXCEPT
Definition blur.h:153
float sinf(float value) FL_NO_EXCEPT
Definition math.h:360
constexpr enable_if< is_fixed_point< T >::value, T >::type clamp(T x, T lo, T hi) FL_NO_EXCEPT
void fadeToBlackBy(CRGB *leds, fl::u16 num_leds, fl::u8 fadeBy) FL_NO_EXCEPT
constexpr enable_if< is_fixed_point< T >::value, T >::type ceil(T x) FL_NO_EXCEPT
float cosf(float value) FL_NO_EXCEPT
Definition math.h:366
Base definition for an LED controller.