FastLED 3.9.15
Loading...
Searching...
No Matches
Luminova.h
Go to the documentation of this file.
1#include <FastLED.h>
2
3
4// ===== matrix + LED config =====
5#define WIDTH 32
6#define HEIGHT 32
7#define NUM_LEDS (WIDTH * HEIGHT)
8
9#define DATA_PIN 3
10#define LED_TYPE WS2812B
11#define COLOR_ORDER GRB
12#define BRIGHTNESS 96
13
14using fl::u16;
15
16// Set to 1 if your panel is serpentine; 0 for progressive rows
17const bool kMatrixSerpentineLayout = true;
18// Scale down per-dot intensity to avoid blowout on small grids
19const uint8_t kPointGain = 128; // 50%
20
22
23// UI control for animation speed (telemetry + control)
24
25// Provide the XY() function FastLED expects (in fl namespace) so blur2d can map
26// properly.
27namespace fl {
28fl::u16 XY(fl::u16 x, fl::u16 y) {
29 if (x >= WIDTH || y >= HEIGHT)
30 return 0;
32 if (y & 1) {
33 // odd rows run right-to-left
34 return y * WIDTH + (WIDTH - 1 - x);
35 } else {
36 // even rows run left-to-right
37 return y * WIDTH + x;
38 }
39 } else {
40 return y * WIDTH + x;
41 }
42}
43} // namespace fl
44
45// ===== particle sim (Processing port) =====
46struct P {
47 float x, y; // position
48 float a; // angle
49 int f; // direction (+1 or -1)
50 int g; // group (I in the original)
51 float s; // "stroke weight" / intensity
52 bool alive; // quick guard in case we want to reuse slots
53};
54
55static uint32_t t = 0; // frame-ish counter
56static const int MAXP = 256; // fewer particles for small grids
58
59void resetParticle(P &p, uint32_t tt) {
60 // Original: x=360,y=360 (center), a=t*1.25 + noise(I)*W, f=t%2*2-1, g=I,
61 // s=5
62 int I = (int)(tt / 50);
63 p.x = (WIDTH - 1) / 2.0f;
64 p.y = (HEIGHT - 1) / 2.0f;
65
66 // noise(I)*W -> use 1D Perlin noise via inoise8
67 uint8_t n1 = inoise8(I * 19); // arbitrary scale
68 float noiseW = (n1 / 255.0f) * WIDTH;
69
70 p.a = tt * 1.25f + noiseW; // base angle component
71 p.f = (tt & 1) ? +1 : -1; // alternate direction
72 p.g = I;
73 p.s = 3.0f; // lower initial intensity for small grids
74 p.alive = true;
75}
76
77inline void plotDot(int x, int y, uint8_t v) {
79 return;
80 // Additive white (Processing used stroke(W), i.e., white) with gain control
81 leds[fl::XY((fl::u8)x, (fl::u8)y)] += CHSV(0, 0, scale8(v, kPointGain));
82}
83
84// draw a small disk ~ strokeWeight; 1..3 pixels radius
85void plotSoftDot(float fx, float fy, float s) {
86 // map s (decays from 5) to a pixel radius 1..3
87 float r = constrain(s * 0.5f, 1.0f, 3.0f);
88 int R = (int)fl::ceilf(r);
89 int cx = (int)fl::roundf(fx);
90 int cy = (int)fl::roundf(fy);
91 float r2 = r * r;
92 for (int dy = -R; dy <= R; ++dy) {
93 for (int dx = -R; dx <= R; ++dx) {
94 float d2 = dx * dx + dy * dy;
95 if (d2 <= r2) {
96 // falloff toward edge
97 float fall = 1.0f - (d2 / (r2 + 0.0001f));
98 uint8_t v = (uint8_t)constrain(255.0f * fall, 0.0f, 255.0f);
99 plotDot(cx + dx, cy + dy, v);
100 }
101 }
102 }
103}
104
105void setup() {
108 FastLED.setBrightness(BRIGHTNESS);
109 FastLED.clear(true);
110 // When user adjusts UI, reflect into model speed
111 // Provide screen map to UI with a specific LED diameter
115 fl::ScreenMap screenmap = xy.toScreenMap();
116 screenmap.setDiameter(0.15f);
117 controller->setScreenMap(screenmap);
118 // init particles as "dead"
119 for (int i = 0; i < MAXP; ++i)
120 ps[i].alive = false;
121}
122
123
124
125// Needed for proper blur mapping.
126u16 xy_map_function(u16 x, u16 y, u16 width, u16 height) { return fl::XY(x, y); }
128
129void loop() {
130 // Processing does: background(0, t?9:!createCanvas(...)+W); filter(BLUR)
131 // We emulate a very light global fade + blur to leave trails.
132 // First a tiny global fade, then a mild Gaussian-ish blur.
133 fadeToBlackBy(leds, NUM_LEDS, 18); // stronger fade to prevent blowout
134 blur2d(leds, WIDTH, HEIGHT, 24, xymap); // slightly gentler blur for 32x32
135
136 // Spawn/overwrite one particle per frame, round-robin
137 resetParticle(ps[t % MAXP], t);
138
139 // Update & draw all particles
140 for (int i = 0; i < MAXP; ++i) {
141 if (!ps[i].alive)
142 continue;
143 P &p = ps[i];
144
145 // strokeWeight(p.s *= .997)
146 p.s *= 0.997f;
147 if (p.s < 0.5f) {
148 p.alive = false;
149 continue;
150 } // cheap cull
151
152 // a += (noise(t/99, p.g) - .5) / 9
153 // Use 2D noise: (t/99, g). inoise8 returns 0..255; center at ~128.
154 float tOver99 = (float)t / 99.0f;
155 uint8_t n2 = inoise8((uint16_t)(tOver99 * 4096), (uint16_t)(p.g * 37));
156 float n2c = ((int)n2 - 128) / 255.0f; // ~ -0.5 .. +0.5
157 p.a += (n2c) / 9.0f;
158
159 // x += cos((a)*f), y += sin(a*f) (original had (a+=...)*f inside cos)
160 float aa = p.a * (float)p.f;
161 p.x += fl::cosf(aa);
162 p.y += fl::sinf(aa);
163
164 // draw white point with softness according to s
165 plotSoftDot(p.x, p.y, p.s);
166 }
167
168 FastLED.show();
169 t++;
170 // Cap frame rate a bit like Processing's draw loop
171 FastLED.delay(16); // ~60 FPS
172}
173
174/*** Tips
175 * - Want sharper trails? Lower blur2d strength or raise fadeToBlackBy amount.
176 * - Too many or too few particles? Tweak MAXP.
177 * - Want color instead of white? Replace plotDot/plotSoftDot to use CHSV with
178 * hue based on p.g or p.a.
179 * - If your matrix isn't serpentine, set kMatrixSerpentineLayout=false.
180 */
#define COLOR_ORDER
#define NUM_LEDS
fl::CRGB leds[NUM_LEDS]
#define BRIGHTNESS
XYMap xymap
fl::ScreenMap screenmap
int y
Definition simple.h:93
int x
Definition simple.h:92
#define DATA_PIN
Definition ClientReal.h:82
FL_DISABLE_WARNING_PUSH FL_DISABLE_WARNING_GLOBAL_CONSTRUCTORS CFastLED FastLED
Global LED strip management instance.
CLEDController * controller
#define kMatrixSerpentineLayout
unsigned int xy(unsigned int x, unsigned int y)
#define WIDTH
#define LED_TYPE
#define HEIGHT
static XYMap constructWithUserFunction(u16 width, u16 height, XYFunction xyFunction, u16 offset=0) FL_NOEXCEPT
Definition xymap.cpp.hpp:27
static XYMap constructSerpentine(u16 width, u16 height, u16 offset=0) FL_NOEXCEPT
Definition xymap.cpp.hpp:53
static XYMap constructRectangularGrid(u16 width, u16 height, u16 offset=0) FL_NOEXCEPT
Definition xymap.cpp.hpp:35
fl::CLEDController CLEDController
void fadeToBlackBy(CRGB *leds, fl::u16 num_leds, fl::u8 fadeBy)
void blur2d(fl::span< CRGB > leds, u8 width, u8 height, fract8 blur_amount, const XYMap &xymap) FL_NOEXCEPT
Definition blur.h:153
const uint8_t kPointGain
Definition Luminova.h:19
void plotSoftDot(float fx, float fy, float s)
Definition Luminova.h:85
u16 xy_map_function(u16 x, u16 y, u16 width, u16 height)
Definition Luminova.h:126
void setup()
Definition Luminova.h:105
void plotDot(int x, int y, uint8_t v)
Definition Luminova.h:77
void resetParticle(P &p, uint32_t tt)
Definition Luminova.h:59
static const int MAXP
Definition Luminova.h:56
static uint32_t t
Definition Luminova.h:55
P ps[MAXP]
Definition Luminova.h:57
void loop()
Definition Luminova.h:129
int g
Definition Luminova.h:50
int f
Definition Luminova.h:49
bool alive
Definition Luminova.h:52
float y
Definition Luminova.h:47
float s
Definition Luminova.h:51
float a
Definition Luminova.h:48
float x
Definition Luminova.h:47
Definition Luminova.h:46
fl::hsv8 CHSV
Definition chsv.h:11
fl::CRGB CRGB
Definition crgb.h:25
fl::u8 inoise8(fl::u16 x, fl::u16 y, fl::u16 z)
unsigned char u8
Definition stdint.h:131
float roundf(float value) FL_NOEXCEPT
Definition math.h:316
float sinf(float value) FL_NOEXCEPT
Definition math.h:352
float ceilf(float value) FL_NOEXCEPT
Definition math.h:310
fl::u16 XY(fl::u16 x, fl::u16 y)
Definition Luminova.h:28
float cosf(float value) FL_NOEXCEPT
Definition math.h:358
Base definition for an LED controller.
Definition crgb.hpp:179