GCC Code Coverage Report


Directory: ./
File: overlays/wled/noise.cpp
Date: 2026-10-29 08:11:58
Exec Total Coverage
Lines: 0 419 0.0%
Functions: 0 25 0.0%
Branches: 0 638 0.0%

Line Branch Exec Source
1 /// @file noise.cpp
2 /// Functions to generate and fill arrays with noise.
3
4 #include <string.h>
5 #include "fl/array.h"
6
7
8 /// Disables pragma messages and warnings
9 #define FASTLED_INTERNAL
10 #include "FastLED.h"
11
12
13 // Compiler throws a warning about stack usage possibly being unbounded even
14 // though bounds are checked, silence that so users don't see it
15 #pragma GCC diagnostic push
16 #pragma GCC diagnostic ignored "-Wstack-usage="
17
18
19
20 /// Reads a single byte from the p array
21 #define P(x) FL_PGM_READ_BYTE_NEAR(p + x)
22
23 FASTLED_NAMESPACE_BEGIN
24
25
26 FL_PROGMEM static uint8_t const p[] = {
27 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225,
28 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148,
29 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32,
30 57, 177, 33, 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175,
31 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122,
32 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143, 54,
33 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169,
34 200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64,
35 52, 217, 226, 250, 124, 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212,
36 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42, 223, 183, 170, 213,
37 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9,
38 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104,
39 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241,
40 81, 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157,
41 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93,
42 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180,
43 151};
44
45
46 // Start Doxygen define hiding
47 /// @cond
48
49 #if FASTLED_NOISE_ALLOW_AVERAGE_TO_OVERFLOW == 1
50 #define AVG15(U,V) (((U)+(V)) >> 1)
51 #else
52 // See if we should use the inlined avg15 for AVR with MUL instruction
53 #if defined(__AVR__) && (LIB8_ATTINY == 0)
54 #define AVG15(U,V) (avg15_inline_avr_mul((U),(V)))
55 // inlined copy of avg15 for AVR with MUL instruction; cloned from math8.h
56 // Forcing this inline in the 3-D 16bit noise produces a 12% speedup overall,
57 // at a cost of just +8 bytes of net code size.
58 static int16_t inline __attribute__((always_inline)) avg15_inline_avr_mul( int16_t i, int16_t j)
59 {
60 asm volatile(
61 /* first divide j by 2, throwing away lowest bit */
62 "asr %B[j] \n\t"
63 "ror %A[j] \n\t"
64 /* now divide i by 2, with lowest bit going into C */
65 "asr %B[i] \n\t"
66 "ror %A[i] \n\t"
67 /* add j + C to i */
68 "adc %A[i], %A[j] \n\t"
69 "adc %B[i], %B[j] \n\t"
70 : [i] "+r" (i)
71 : [j] "r" (j) );
72 return i;
73 }
74 #else
75 #define AVG15(U,V) (avg15((U),(V)))
76 #endif
77 #endif
78
79 // See fastled_config.h for notes on this;
80 // "#define FASTLED_NOISE_FIXED 1" is the correct value
81 #if FASTLED_NOISE_FIXED == 0
82 #define EASE8(x) (FADE(x) )
83 #define EASE16(x) (FADE(x) )
84 #else
85 #define EASE8(x) (ease8InOutQuad(x) )
86 #define EASE16(x) (ease16InOutQuad(x))
87 #endif
88 //
89 // #define FADE_12
90 #define FADE_16
91
92 #ifdef FADE_12
93 #define FADE logfade12
94 #define LERP(a,b,u) lerp15by12(a,b,u)
95 #else
96 #define FADE(x) scale16(x,x)
97 #define LERP(a,b,u) lerp15by16(a,b,u)
98 #endif
99
100 // end Doxygen define hiding
101 /// @endcond
102
103 static int16_t inline __attribute__((always_inline)) grad16(uint8_t hash, int16_t x, int16_t y, int16_t z) {
104 #if 0
105 switch(hash & 0xF) {
106 case 0: return (( x) + ( y))>>1;
107 case 1: return ((-x) + ( y))>>1;
108 case 2: return (( x) + (-y))>>1;
109 case 3: return ((-x) + (-y))>>1;
110 case 4: return (( x) + ( z))>>1;
111 case 5: return ((-x) + ( z))>>1;
112 case 6: return (( x) + (-z))>>1;
113 case 7: return ((-x) + (-z))>>1;
114 case 8: return (( y) + ( z))>>1;
115 case 9: return ((-y) + ( z))>>1;
116 case 10: return (( y) + (-z))>>1;
117 case 11: return ((-y) + (-z))>>1;
118 case 12: return (( y) + ( x))>>1;
119 case 13: return ((-y) + ( z))>>1;
120 case 14: return (( y) + (-x))>>1;
121 case 15: return ((-y) + (-z))>>1;
122 }
123 #else
124 ✗ hash = hash&15;
125 ✗ int16_t u = hash<8?x:y;
126 ✗ int16_t v = hash<4?y:hash==12||hash==14?x:z;
127 ✗ if(hash&1) { u = -u; }
128 ✗ if(hash&2) { v = -v; }
129
130 ✗ return AVG15(u,v);
131 #endif
132 }
133
134 static int16_t inline __attribute__((always_inline)) grad16(uint8_t hash, int16_t x, int16_t y) {
135 ✗ hash = hash & 7;
136 int16_t u,v;
137 ✗ if(hash < 4) { u = x; v = y; } else { u = y; v = x; }
138 ✗ if(hash&1) { u = -u; }
139 ✗ if(hash&2) { v = -v; }
140
141 ✗ return AVG15(u,v);
142 }
143
144 static int16_t inline __attribute__((always_inline)) grad16(uint8_t hash, int16_t x) {
145 ✗ hash = hash & 15;
146 int16_t u,v;
147 ✗ if(hash > 8) { u=x;v=x; }
148 ✗ else if(hash < 4) { u=x;v=1; }
149 ✗ else { u=1;v=x; }
150 ✗ if(hash&1) { u = -u; }
151 ✗ if(hash&2) { v = -v; }
152
153 ✗ return AVG15(u,v);
154 }
155
156 // selectBasedOnHashBit performs this:
157 // result = (hash & (1<<bitnumber)) ? a : b
158 // but with an AVR asm version that's smaller and quicker than C
159 // (and probably not worth including in lib8tion)
160 static int8_t inline __attribute__((always_inline)) selectBasedOnHashBit(uint8_t hash, uint8_t bitnumber, int8_t a, int8_t b) {
161 int8_t result;
162 #if !defined(__AVR__)
163 ✗ result = (hash & (1<<bitnumber)) ? a : b;
164 #else
165 asm volatile(
166 "mov %[result],%[a] \n\t"
167 "sbrs %[hash],%[bitnumber] \n\t"
168 "mov %[result],%[b] \n\t"
169 : [result] "=r" (result)
170 : [hash] "r" (hash),
171 [bitnumber] "M" (bitnumber),
172 [a] "r" (a),
173 [b] "r" (b)
174 );
175 #endif
176 ✗ return result;
177 }
178
179 static int8_t inline __attribute__((always_inline)) grad8(uint8_t hash, int8_t x, int8_t y, int8_t z) {
180 #if 0
181 switch(hash & 0xF) {
182 case 0: return (( x) + ( y))>>1;
183 case 1: return ((-x) + ( y))>>1;
184 case 2: return (( x) + (-y))>>1;
185 case 3: return ((-x) + (-y))>>1;
186 case 4: return (( x) + ( z))>>1;
187 case 5: return ((-x) + ( z))>>1;
188 case 6: return (( x) + (-z))>>1;
189 case 7: return ((-x) + (-z))>>1;
190 case 8: return (( y) + ( z))>>1;
191 case 9: return ((-y) + ( z))>>1;
192 case 10: return (( y) + (-z))>>1;
193 case 11: return ((-y) + (-z))>>1;
194 case 12: return (( y) + ( x))>>1;
195 case 13: return ((-y) + ( z))>>1;
196 case 14: return (( y) + (-x))>>1;
197 case 15: return ((-y) + (-z))>>1;
198 }
199 #else
200
201 ✗ hash &= 0xF;
202
203 int8_t u, v;
204 //u = (hash&8)?y:x;
205 ✗ u = selectBasedOnHashBit( hash, 3, y, x);
206
207 #if 1
208 ✗ v = hash<4?y:hash==12||hash==14?x:z;
209 #else
210 // Verbose version for analysis; generates idenitical code.
211 if( hash < 4) { // 00 01 02 03
212 v = y;
213 } else {
214 if( hash==12 || hash==14) { // 0C 0E
215 v = x;
216 } else {
217 v = z; // 04 05 06 07 08 09 0A 0B 0D 0F
218 }
219 }
220 #endif
221
222 ✗ if(hash&1) { u = -u; }
223 ✗ if(hash&2) { v = -v; }
224
225 ✗ return avg7(u,v);
226 #endif
227 }
228
229 static int8_t inline __attribute__((always_inline)) grad8(uint8_t hash, int8_t x, int8_t y)
230 {
231 // since the tests below can be done bit-wise on the bottom
232 // three bits, there's no need to mask off the higher bits
233 // hash = hash & 7;
234
235 int8_t u,v;
236 ✗ if( hash & 4) {
237 ✗ u = y; v = x;
238 } else {
239 ✗ u = x; v = y;
240 }
241
242 ✗ if(hash&1) { u = -u; }
243 ✗ if(hash&2) { v = -v; }
244
245 ✗ return avg7(u,v);
246 }
247
248 static int8_t inline __attribute__((always_inline)) grad8(uint8_t hash, int8_t x)
249 {
250 // since the tests below can be done bit-wise on the bottom
251 // four bits, there's no need to mask off the higher bits
252 // hash = hash & 15;
253
254 int8_t u,v;
255 ✗ if(hash & 8) {
256 ✗ u=x; v=x;
257 } else {
258 ✗ if(hash & 4) {
259 ✗ u=1; v=x;
260 } else {
261 ✗ u=x; v=1;
262 }
263 }
264
265 ✗ if(hash&1) { u = -u; }
266 ✗ if(hash&2) { v = -v; }
267
268 ✗ return avg7(u,v);
269 }
270
271
272 #ifdef FADE_12
273 uint16_t logfade12(uint16_t val) {
274 return scale16(val,val)>>4;
275 }
276
277 static int16_t inline __attribute__((always_inline)) lerp15by12( int16_t a, int16_t b, fract16 frac)
278 {
279 //if(1) return (lerp(frac,a,b));
280 int16_t result;
281 if( b > a) {
282 uint16_t delta = b - a;
283 uint16_t scaled = scale16(delta,frac<<4);
284 result = a + scaled;
285 } else {
286 uint16_t delta = a - b;
287 uint16_t scaled = scale16(delta,frac<<4);
288 result = a - scaled;
289 }
290 return result;
291 }
292 #endif
293
294 static int8_t inline __attribute__((always_inline)) lerp7by8( int8_t a, int8_t b, fract8 frac)
295 {
296 // int8_t delta = b - a;
297 // int16_t prod = (uint16_t)delta * (uint16_t)frac;
298 // int8_t scaled = prod >> 8;
299 // int8_t result = a + scaled;
300 // return result;
301 int8_t result;
302 ✗ if( b > a) {
303 ✗ uint8_t delta = b - a;
304 ✗ uint8_t scaled = scale8( delta, frac);
305 ✗ result = a + scaled;
306 } else {
307 ✗ uint8_t delta = a - b;
308 ✗ uint8_t scaled = scale8( delta, frac);
309 ✗ result = a - scaled;
310 }
311 ✗ return result;
312 }
313
314 ✗ int16_t inoise16_raw(uint32_t x, uint32_t y, uint32_t z)
315 {
316 // Find the unit cube containing the point
317 ✗ uint8_t X = (x>>16)&0xFF;
318 ✗ uint8_t Y = (y>>16)&0xFF;
319 ✗ uint8_t Z = (z>>16)&0xFF;
320
321 // Hash cube corner coordinates
322 ✗ uint8_t A = P(X)+Y;
323 ✗ uint8_t AA = P(A)+Z;
324 ✗ uint8_t AB = P(A+1)+Z;
325 ✗ uint8_t B = P(X+1)+Y;
326 ✗ uint8_t BA = P(B) + Z;
327 ✗ uint8_t BB = P(B+1)+Z;
328
329 // Get the relative position of the point in the cube
330 ✗ uint16_t u = x & 0xFFFF;
331 ✗ uint16_t v = y & 0xFFFF;
332 ✗ uint16_t w = z & 0xFFFF;
333
334 // Get a signed version of the above for the grad function
335 ✗ int16_t xx = (u >> 1) & 0x7FFF;
336 ✗ int16_t yy = (v >> 1) & 0x7FFF;
337 ✗ int16_t zz = (w >> 1) & 0x7FFF;
338 ✗ uint16_t N = 0x8000L;
339
340 ✗ u = EASE16(u); v = EASE16(v); w = EASE16(w);
341
342 // skip the log fade adjustment for the moment, otherwise here we would
343 // adjust fade values for u,v,w
344 ✗ int16_t X1 = LERP(grad16(P(AA), xx, yy, zz), grad16(P(BA), xx - N, yy, zz), u);
345 ✗ int16_t X2 = LERP(grad16(P(AB), xx, yy-N, zz), grad16(P(BB), xx - N, yy - N, zz), u);
346 ✗ int16_t X3 = LERP(grad16(P(AA+1), xx, yy, zz-N), grad16(P(BA+1), xx - N, yy, zz-N), u);
347 ✗ int16_t X4 = LERP(grad16(P(AB+1), xx, yy-N, zz-N), grad16(P(BB+1), xx - N, yy - N, zz - N), u);
348
349 ✗ int16_t Y1 = LERP(X1,X2,v);
350 ✗ int16_t Y2 = LERP(X3,X4,v);
351
352 ✗ int16_t ans = LERP(Y1,Y2,w);
353
354 ✗ return ans;
355 }
356
357 ✗ int16_t inoise16_raw(uint32_t x, uint32_t y, uint32_t z, uint32_t t) {
358 // 1. Extract the integer (grid) parts.
359 ✗ uint8_t X = (x >> 16) & 0xFF;
360 ✗ uint8_t Y = (y >> 16) & 0xFF;
361 ✗ uint8_t Z = (z >> 16) & 0xFF;
362 ✗ uint8_t T = (t >> 16) & 0xFF;
363
364 // 2. Extract the fractional parts.
365 ✗ uint16_t u = x & 0xFFFF;
366 ✗ uint16_t v = y & 0xFFFF;
367 ✗ uint16_t w = z & 0xFFFF;
368 ✗ uint16_t s = t & 0xFFFF;
369
370 // 3. Easing of the fractional parts.
371 ✗ u = EASE16(u);
372 ✗ v = EASE16(v);
373 ✗ w = EASE16(w);
374 ✗ s = EASE16(s);
375
376 ✗ uint16_t N = 0x8000L; // fixed-point half-scale
377
378 // 4. Precompute fixed-point versions for the gradient evaluations.
379 ✗ int16_t xx = (u >> 1) & 0x7FFF;
380 ✗ int16_t yy = (v >> 1) & 0x7FFF;
381 ✗ int16_t zz = (w >> 1) & 0x7FFF;
382
383 // 5. Hash the 3D cube corners (the “base” for both t slices).
384 ✗ uint8_t A = P(X) + Y;
385 ✗ uint8_t AA = P(A) + Z;
386 ✗ uint8_t AB = P(A + 1) + Z;
387 ✗ uint8_t B = P(X + 1) + Y;
388 ✗ uint8_t BA = P(B) + Z;
389 ✗ uint8_t BB = P(B + 1) + Z;
390
391 // 6. --- Lower t Slice (using T) ---
392 ✗ uint8_t AAA = P(AA) + T;
393 ✗ uint8_t AAB = P(AA + 1) + T;
394 ✗ uint8_t ABA = P(AB) + T;
395 ✗ uint8_t ABB = P(AB + 1) + T;
396 ✗ uint8_t BAA = P(BA) + T;
397 ✗ uint8_t BAB = P(BA + 1) + T;
398 ✗ uint8_t BBA = P(BB) + T;
399 ✗ uint8_t BBB = P(BB + 1) + T;
400
401 ✗ int16_t L1 = LERP(grad16(AAA, xx, yy, zz), grad16(BAA, xx - N, yy, zz), u);
402 ✗ int16_t L2 = LERP(grad16(ABA, xx, yy - N, zz), grad16(BBA, xx - N, yy - N, zz), u);
403 ✗ int16_t L3 = LERP(grad16(AAB, xx, yy, zz - N), grad16(BAB, xx - N, yy, zz - N), u);
404 ✗ int16_t L4 = LERP(grad16(ABB, xx, yy - N, zz - N), grad16(BBB, xx - N, yy - N, zz - N), u);
405
406 ✗ int16_t Y1 = LERP(L1, L2, v);
407 ✗ int16_t Y2 = LERP(L3, L4, v);
408 ✗ int16_t noise_lower = LERP(Y1, Y2, w);
409
410 // 7. --- Upper t Slice (using T+1) ---
411 ✗ uint8_t Tupper = T + 1;
412 ✗ uint8_t AAA_u = P(AA) + Tupper;
413 ✗ uint8_t AAB_u = P(AA + 1) + Tupper;
414 ✗ uint8_t ABA_u = P(AB) + Tupper;
415 ✗ uint8_t ABB_u = P(AB + 1) + Tupper;
416 ✗ uint8_t BAA_u = P(BA) + Tupper;
417 ✗ uint8_t BAB_u = P(BA + 1) + Tupper;
418 ✗ uint8_t BBA_u = P(BB) + Tupper;
419 ✗ uint8_t BBB_u = P(BB + 1) + Tupper;
420
421 ✗ int16_t U1 = LERP(grad16(AAA_u, xx, yy, zz), grad16(BAA_u, xx - N, yy, zz), u);
422 ✗ int16_t U2 = LERP(grad16(ABA_u, xx, yy - N, zz), grad16(BBA_u, xx - N, yy - N, zz), u);
423 ✗ int16_t U3 = LERP(grad16(AAB_u, xx, yy, zz - N), grad16(BAB_u, xx - N, yy, zz - N), u);
424 ✗ int16_t U4 = LERP(grad16(ABB_u, xx, yy - N, zz - N), grad16(BBB_u, xx - N, yy - N, zz - N), u);
425
426 ✗ int16_t V1 = LERP(U1, U2, v);
427 ✗ int16_t V2 = LERP(U3, U4, v);
428 ✗ int16_t noise_upper = LERP(V1, V2, w);
429
430 // 8. Final interpolation in the t dimension.
431 ✗ int16_t noise4d = LERP(noise_lower, noise_upper, s);
432
433 ✗ return noise4d;
434 }
435
436 ✗ uint16_t inoise16(uint32_t x, uint32_t y, uint32_t z, uint32_t t) {
437 ✗ int32_t ans = inoise16_raw(x,y,z,t);
438 ✗ ans = ans + 19052L;
439 ✗ uint32_t pan = ans;
440 // pan = (ans * 220L) >> 7. That's the same as:
441 // pan = (ans * 440L) >> 8. And this way avoids a 7X four-byte shift-loop on AVR.
442 // Identical math, except for the highest bit, which we don't care about anyway,
443 // since we're returning the 'middle' 16 out of a 32-bit value anyway.
444 ✗ pan *= 440L;
445 ✗ return (pan>>8);
446
447 // return scale16by8(pan,220)<<1;
448 // return ((inoise16_raw(x,y,z)+19052)*220)>>7;
449 // return scale16by8(inoise16_raw(x,y,z)+19052,220)<<1;
450 }
451
452 ✗ uint16_t inoise16(uint32_t x, uint32_t y, uint32_t z) {
453 ✗ int32_t ans = inoise16_raw(x,y,z);
454 ✗ ans = ans + 19052L;
455 ✗ uint32_t pan = ans;
456 // pan = (ans * 220L) >> 7. That's the same as:
457 // pan = (ans * 440L) >> 8. And this way avoids a 7X four-byte shift-loop on AVR.
458 // Identical math, except for the highest bit, which we don't care about anyway,
459 // since we're returning the 'middle' 16 out of a 32-bit value anyway.
460 ✗ pan *= 440L;
461 ✗ return (pan>>8);
462
463 // // return scale16by8(pan,220)<<1;
464 // return ((inoise16_raw(x,y,z)+19052)*220)>>7;
465 // return scale16by8(inoise16_raw(x,y,z)+19052,220)<<1;
466 }
467
468 ✗ int16_t inoise16_raw(uint32_t x, uint32_t y)
469 {
470 // Find the unit cube containing the point
471 ✗ uint8_t X = x>>16;
472 ✗ uint8_t Y = y>>16;
473
474 // Hash cube corner coordinates
475 ✗ uint8_t A = P(X)+Y;
476 ✗ uint8_t AA = P(A);
477 ✗ uint8_t AB = P(A+1);
478 ✗ uint8_t B = P(X+1)+Y;
479 ✗ uint8_t BA = P(B);
480 ✗ uint8_t BB = P(B+1);
481
482 // Get the relative position of the point in the cube
483 ✗ uint16_t u = x & 0xFFFF;
484 ✗ uint16_t v = y & 0xFFFF;
485
486 // Get a signed version of the above for the grad function
487 ✗ int16_t xx = (u >> 1) & 0x7FFF;
488 ✗ int16_t yy = (v >> 1) & 0x7FFF;
489 ✗ uint16_t N = 0x8000L;
490
491 ✗ u = EASE16(u); v = EASE16(v);
492
493 ✗ int16_t X1 = LERP(grad16(P(AA), xx, yy), grad16(P(BA), xx - N, yy), u);
494 ✗ int16_t X2 = LERP(grad16(P(AB), xx, yy-N), grad16(P(BB), xx - N, yy - N), u);
495
496 ✗ int16_t ans = LERP(X1,X2,v);
497
498 ✗ return ans;
499 }
500
501 ✗ uint16_t inoise16(uint32_t x, uint32_t y) {
502 ✗ int32_t ans = inoise16_raw(x,y);
503 ✗ ans = ans + 17308L;
504 ✗ uint32_t pan = ans;
505 // pan = (ans * 242L) >> 7. That's the same as:
506 // pan = (ans * 484L) >> 8. And this way avoids a 7X four-byte shift-loop on AVR.
507 // Identical math, except for the highest bit, which we don't care about anyway,
508 // since we're returning the 'middle' 16 out of a 32-bit value anyway.
509 ✗ pan *= 484L;
510 ✗ return (pan>>8);
511
512 // return (uint32_t)(((int32_t)inoise16_raw(x,y)+(uint32_t)17308)*242)>>7;
513 // return scale16by8(inoise16_raw(x,y)+17308,242)<<1;
514 }
515
516 ✗ int16_t inoise16_raw(uint32_t x)
517 {
518 // Find the unit cube containing the point
519 ✗ uint8_t X = x>>16;
520
521 // Hash cube corner coordinates
522 ✗ uint8_t A = P(X);
523 ✗ uint8_t AA = P(A);
524 ✗ uint8_t B = P(X+1);
525 ✗ uint8_t BA = P(B);
526
527 // Get the relative position of the point in the cube
528 ✗ uint16_t u = x & 0xFFFF;
529
530 // Get a signed version of the above for the grad function
531 ✗ int16_t xx = (u >> 1) & 0x7FFF;
532 ✗ uint16_t N = 0x8000L;
533
534 ✗ u = EASE16(u);
535
536 ✗ int16_t ans = LERP(grad16(P(AA), xx), grad16(P(BA), xx - N), u);
537
538 ✗ return ans;
539 }
540
541 ✗ uint16_t inoise16(uint32_t x) {
542 ✗ return ((uint32_t)((int32_t)inoise16_raw(x) + 17308L)) << 1;
543 }
544
545 ✗ int8_t inoise8_raw(uint16_t x, uint16_t y, uint16_t z)
546 {
547 // Find the unit cube containing the point
548 ✗ uint8_t X = x>>8;
549 ✗ uint8_t Y = y>>8;
550 ✗ uint8_t Z = z>>8;
551
552 // Hash cube corner coordinates
553 ✗ uint8_t A = P(X)+Y;
554 ✗ uint8_t AA = P(A)+Z;
555 ✗ uint8_t AB = P(A+1)+Z;
556 ✗ uint8_t B = P(X+1)+Y;
557 ✗ uint8_t BA = P(B) + Z;
558 ✗ uint8_t BB = P(B+1)+Z;
559
560 // Get the relative position of the point in the cube
561 ✗ uint8_t u = x;
562 ✗ uint8_t v = y;
563 ✗ uint8_t w = z;
564
565 // Get a signed version of the above for the grad function
566 ✗ int8_t xx = ((uint8_t)(x)>>1) & 0x7F;
567 ✗ int8_t yy = ((uint8_t)(y)>>1) & 0x7F;
568 ✗ int8_t zz = ((uint8_t)(z)>>1) & 0x7F;
569 ✗ uint8_t N = 0x80;
570
571 ✗ u = EASE8(u); v = EASE8(v); w = EASE8(w);
572
573 ✗ int8_t X1 = lerp7by8(grad8(P(AA), xx, yy, zz), grad8(P(BA), xx - N, yy, zz), u);
574 ✗ int8_t X2 = lerp7by8(grad8(P(AB), xx, yy-N, zz), grad8(P(BB), xx - N, yy - N, zz), u);
575 ✗ int8_t X3 = lerp7by8(grad8(P(AA+1), xx, yy, zz-N), grad8(P(BA+1), xx - N, yy, zz-N), u);
576 ✗ int8_t X4 = lerp7by8(grad8(P(AB+1), xx, yy-N, zz-N), grad8(P(BB+1), xx - N, yy - N, zz - N), u);
577
578 ✗ int8_t Y1 = lerp7by8(X1,X2,v);
579 ✗ int8_t Y2 = lerp7by8(X3,X4,v);
580
581 ✗ int8_t ans = lerp7by8(Y1,Y2,w);
582
583 ✗ return ans;
584 }
585
586 ✗ uint8_t inoise8(uint16_t x, uint16_t y, uint16_t z) {
587 //return scale8(76+(inoise8_raw(x,y,z)),215)<<1;
588 ✗ int8_t n = inoise8_raw( x, y, z); // -64..+64
589 ✗ n+= 64; // 0..128
590 ✗ uint8_t ans = qadd8( n, n); // 0..255
591 ✗ return ans;
592 }
593
594 ✗ int8_t inoise8_raw(uint16_t x, uint16_t y)
595 {
596 // Find the unit cube containing the point
597 ✗ uint8_t X = x>>8;
598 ✗ uint8_t Y = y>>8;
599
600 // Hash cube corner coordinates
601 ✗ uint8_t A = P(X)+Y;
602 ✗ uint8_t AA = P(A);
603 ✗ uint8_t AB = P(A+1);
604 ✗ uint8_t B = P(X+1)+Y;
605 ✗ uint8_t BA = P(B);
606 ✗ uint8_t BB = P(B+1);
607
608 // Get the relative position of the point in the cube
609 ✗ uint8_t u = x;
610 ✗ uint8_t v = y;
611
612 // Get a signed version of the above for the grad function
613 ✗ int8_t xx = ((uint8_t)(x)>>1) & 0x7F;
614 ✗ int8_t yy = ((uint8_t)(y)>>1) & 0x7F;
615 ✗ uint8_t N = 0x80;
616
617 ✗ u = EASE8(u); v = EASE8(v);
618
619 ✗ int8_t X1 = lerp7by8(grad8(P(AA), xx, yy), grad8(P(BA), xx - N, yy), u);
620 ✗ int8_t X2 = lerp7by8(grad8(P(AB), xx, yy-N), grad8(P(BB), xx - N, yy - N), u);
621
622 ✗ int8_t ans = lerp7by8(X1,X2,v);
623
624 ✗ return ans;
625 // return scale8((70+(ans)),234)<<1;
626 }
627
628
629
630 ✗ uint8_t inoise8(uint16_t x, uint16_t y) {
631 //return scale8(69+inoise8_raw(x,y),237)<<1;
632 ✗ int8_t n = inoise8_raw( x, y); // -64..+64
633 ✗ n+= 64; // 0..128
634 ✗ uint8_t ans = qadd8( n, n); // 0..255
635 ✗ return ans;
636 }
637
638 // output range = -64 .. +64
639 ✗ int8_t inoise8_raw(uint16_t x)
640 {
641 // Find the unit cube containing the point
642 ✗ uint8_t X = x>>8;
643
644 // Hash cube corner coordinates
645 ✗ uint8_t A = P(X);
646 ✗ uint8_t AA = P(A);
647 ✗ uint8_t B = P(X+1);
648 ✗ uint8_t BA = P(B);
649
650 // Get the relative position of the point in the cube
651 ✗ uint8_t u = x;
652
653 // Get a signed version of the above for the grad function
654 ✗ int8_t xx = ((uint8_t)(x)>>1) & 0x7F;
655 ✗ uint8_t N = 0x80;
656
657 ✗ u = EASE8( u);
658
659 ✗ int8_t ans = lerp7by8(grad8(P(AA), xx), grad8(P(BA), xx - N), u);
660
661 ✗ return ans;
662 }
663
664 ✗ uint8_t inoise8(uint16_t x) {
665 ✗ int8_t n = inoise8_raw(x); //-64..+64
666 ✗ n += 64; // 0..128
667 ✗ uint8_t ans = qadd8(n,n); // 0..255
668 ✗ return ans;
669 }
670
671 // struct q44 {
672 // uint8_t i:4;
673 // uint8_t f:4;
674 // q44(uint8_t _i, uint8_t _f) {i=_i; f=_f; }
675 // };
676
677 // uint32_t mul44(uint32_t v, q44 mulby44) {
678 // return (v *mulby44.i) + ((v * mulby44.f) >> 4);
679 // }
680 //
681 // uint16_t mul44_16(uint16_t v, q44 mulby44) {
682 // return (v *mulby44.i) + ((v * mulby44.f) >> 4);
683 // }
684
685 ✗ void fill_raw_noise8(uint8_t *pData, uint8_t num_points, uint8_t octaves, uint16_t x, int scale, uint16_t time) {
686 ✗ uint32_t _xx = x;
687 ✗ uint32_t scx = scale;
688 ✗ for(int o = 0; o < octaves; ++o) {
689 ✗ for(int i = 0,xx=_xx; i < num_points; ++i, xx+=scx) {
690 ✗ pData[i] = qadd8(pData[i],inoise8(xx,time)>>o);
691 }
692
693 ✗ _xx <<= 1;
694 ✗ scx <<= 1;
695 }
696 ✗ }
697
698 ✗ void fill_raw_noise16into8(uint8_t *pData, uint8_t num_points, uint8_t octaves, uint32_t x, int scale, uint32_t time) {
699 ✗ uint32_t _xx = x;
700 ✗ uint32_t scx = scale;
701 ✗ for(int o = 0; o < octaves; ++o) {
702 ✗ for(int i = 0,xx=_xx; i < num_points; ++i, xx+=scx) {
703 ✗ uint32_t accum = (inoise16(xx,time))>>o;
704 ✗ accum += (pData[i]<<8);
705 ✗ if(accum > 65535) { accum = 65535; }
706 ✗ pData[i] = accum>>8;
707 }
708
709 ✗ _xx <<= 1;
710 ✗ scx <<= 1;
711 }
712 ✗ }
713
714 /// Fill a 2D 8-bit buffer with noise, using inoise8()
715 /// @param pData the array of data to fill with noise values
716 /// @param width the width of the 2D buffer
717 /// @param height the height of the 2D buffer
718 /// @param octaves the number of octaves to use for noise. More octaves = more noise.
719 /// @param freq44 starting octave frequency
720 /// @param amplitude noise amplitude
721 /// @param skip how many noise maps to skip over, incremented recursively per octave
722 /// @param x x-axis coordinate on noise map (1D)
723 /// @param scalex the scale (distance) between x points when filling in noise
724 /// @param y y-axis coordinate on noise map (2D)
725 /// @param scaley the scale (distance) between y points when filling in noise
726 /// @param time the time position for the noise field
727 /// @todo Why isn't this declared in the header (noise.h)?
728 ✗ void fill_raw_2dnoise8(uint8_t *pData, int width, int height, uint8_t octaves, q44 freq44, fract8 amplitude, int skip, uint16_t x, int16_t scalex, uint16_t y, int16_t scaley, uint16_t time) {
729 ✗ if(octaves > 1) {
730 ✗ fill_raw_2dnoise8(pData, width, height, octaves-1, freq44, amplitude, skip+1, x*freq44, freq44 * scalex, y*freq44, freq44 * scaley, time);
731 } else {
732 // amplitude is always 255 on the lowest level
733 ✗ amplitude=255;
734 }
735
736 ✗ scalex *= skip;
737 ✗ scaley *= skip;
738
739 ✗ fract8 invamp = 255-amplitude;
740 ✗ uint16_t xx = x;
741 ✗ for(int i = 0; i < height; ++i, y+=scaley) {
742 ✗ uint8_t *pRow = pData + (i*width);
743 ✗ xx = x;
744 ✗ for(int j = 0; j < width; ++j, xx+=scalex) {
745 ✗ uint8_t noise_base = inoise8(xx,y,time);
746 ✗ noise_base = (0x80 & noise_base) ? (noise_base - 127) : (127 - noise_base);
747 ✗ noise_base = scale8(noise_base<<1,amplitude);
748 ✗ if(skip == 1) {
749 ✗ pRow[j] = scale8(pRow[j],invamp) + noise_base;
750 } else {
751 ✗ for(int ii = i; ii<(i+skip) && ii<height; ++ii) {
752 ✗ uint8_t *pRow = pData + (ii*width);
753 ✗ for(int jj=j; jj<(j+skip) && jj<width; ++jj) {
754 ✗ pRow[jj] = scale8(pRow[jj],invamp) + noise_base;
755 }
756 }
757 }
758 }
759 }
760 ✗ }
761
762 ✗ void fill_raw_2dnoise8(uint8_t *pData, int width, int height, uint8_t octaves, uint16_t x, int scalex, uint16_t y, int scaley, uint16_t time) {
763 ✗ fill_raw_2dnoise8(pData, width, height, octaves, q44(2,0), 128, 1, x, scalex, y, scaley, time);
764 ✗ }
765
766 ✗ void fill_raw_2dnoise16(uint16_t *pData, int width, int height, uint8_t octaves, q88 freq88, fract16 amplitude, int skip, uint32_t x, int32_t scalex, uint32_t y, int32_t scaley, uint32_t time) {
767 ✗ if(octaves > 1) {
768 ✗ fill_raw_2dnoise16(pData, width, height, octaves-1, freq88, amplitude, skip, x *freq88 , scalex *freq88, y * freq88, scaley * freq88, time);
769 } else {
770 // amplitude is always 255 on the lowest level
771 ✗ amplitude=65535;
772 }
773
774 ✗ scalex *= skip;
775 ✗ scaley *= skip;
776 ✗ fract16 invamp = 65535-amplitude;
777 ✗ for(int i = 0; i < height; i+=skip, y+=scaley) {
778 ✗ uint16_t *pRow = pData + (i*width);
779 ✗ for(int j = 0,xx=x; j < width; j+=skip, xx+=scalex) {
780 ✗ uint16_t noise_base = inoise16(xx,y,time);
781 ✗ noise_base = (0x8000 & noise_base) ? noise_base - (32767) : 32767 - noise_base;
782 ✗ noise_base = scale16(noise_base<<1, amplitude);
783 ✗ if(skip==1) {
784 ✗ pRow[j] = scale16(pRow[j],invamp) + noise_base;
785 } else {
786 ✗ for(int ii = i; ii<(i+skip) && ii<height; ++ii) {
787 ✗ uint16_t *pRow = pData + (ii*width);
788 ✗ for(int jj=j; jj<(j+skip) && jj<width; ++jj) {
789 ✗ pRow[jj] = scale16(pRow[jj],invamp) + noise_base;
790 }
791 }
792 }
793 }
794 }
795 ✗ }
796
797 /// Unused
798 /// @todo Remove?
799 int32_t nmin=11111110;
800 /// Unused
801 /// @todo Remove?
802 int32_t nmax=0;
803
804 ✗ void fill_raw_2dnoise16into8(uint8_t *pData, int width, int height, uint8_t octaves, q44 freq44, fract8 amplitude, int skip, uint32_t x, int32_t scalex, uint32_t y, int32_t scaley, uint32_t time) {
805 ✗ if(octaves > 1) {
806 ✗ fill_raw_2dnoise16into8(pData, width, height, octaves-1, freq44, amplitude, skip+1, x*freq44, scalex *freq44, y*freq44, scaley * freq44, time);
807 } else {
808 // amplitude is always 255 on the lowest level
809 ✗ amplitude=255;
810 }
811
812 ✗ scalex *= skip;
813 ✗ scaley *= skip;
814 uint32_t xx;
815 ✗ fract8 invamp = 255-amplitude;
816 ✗ for(int i = 0; i < height; i+=skip, y+=scaley) {
817 ✗ uint8_t *pRow = pData + (i*width);
818 ✗ xx = x;
819 ✗ for(int j = 0; j < width; j+=skip, xx+=scalex) {
820 ✗ uint16_t noise_base = inoise16(xx,y,time);
821 ✗ noise_base = (0x8000 & noise_base) ? noise_base - (32767) : 32767 - noise_base;
822 ✗ noise_base = scale8(noise_base>>7,amplitude);
823 ✗ if(skip==1) {
824 ✗ pRow[j] = qadd8(scale8(pRow[j],invamp),noise_base);
825 } else {
826 ✗ for(int ii = i; ii<(i+skip) && ii<height; ++ii) {
827 ✗ uint8_t *pRow = pData + (ii*width);
828 ✗ for(int jj=j; jj<(j+skip) && jj<width; ++jj) {
829 ✗ pRow[jj] = scale8(pRow[jj],invamp) + noise_base;
830 }
831 }
832 }
833 }
834 }
835 ✗ }
836
837 ✗ void fill_raw_2dnoise16into8(uint8_t *pData, int width, int height, uint8_t octaves, uint32_t x, int scalex, uint32_t y, int scaley, uint32_t time) {
838 ✗ fill_raw_2dnoise16into8(pData, width, height, octaves, q44(2,0), 171, 1, x, scalex, y, scaley, time);
839 ✗ }
840
841 ✗ void fill_noise8(CRGB *leds, int num_leds,
842 uint8_t octaves, uint16_t x, int scale,
843 uint8_t hue_octaves, uint16_t hue_x, int hue_scale,
844 uint16_t time) {
845
846 ✗ if (num_leds <= 0) return;
847
848 ✗ for (int j = 0; j < num_leds; j += 255) {
849 ✗ const int LedsRemaining = num_leds - j;
850 ✗ const int LedsPer = LedsRemaining > 255 ? 255 : LedsRemaining; // limit to 255 max
851
852 ✗ if (LedsPer <= 0) continue;
853 ✗ FASTLED_STACK_ARRAY(uint8_t, V, LedsPer);
854 ✗ FASTLED_STACK_ARRAY(uint8_t, H, LedsPer);
855
856 ✗ memset(V, 0, LedsPer);
857 ✗ memset(H, 0, LedsPer);
858
859 ✗ fill_raw_noise8(V, LedsPer, octaves, x, scale, time);
860 ✗ fill_raw_noise8(H, LedsPer, hue_octaves, hue_x, hue_scale, time);
861
862 ✗ for (int i = 0; i < LedsPer; ++i) {
863 ✗ leds[i + j] = CHSV(H[i], 255, V[i]);
864 }
865 ✗ }
866 }
867
868 ✗ void fill_noise16(CRGB *leds, int num_leds,
869 uint8_t octaves, uint16_t x, int scale,
870 uint8_t hue_octaves, uint16_t hue_x, int hue_scale,
871 uint16_t time, uint8_t hue_shift) {
872
873 ✗ if (num_leds <= 0) return;
874
875 ✗ for (int j = 0; j < num_leds; j += 255) {
876 ✗ const int LedsRemaining = num_leds - j;
877 ✗ const int LedsPer = LedsRemaining > 255 ? 255 : LedsRemaining; // limit to 255 max
878 ✗ if (LedsPer <= 0) continue;
879 ✗ FASTLED_STACK_ARRAY(uint8_t, V, LedsPer);
880 ✗ FASTLED_STACK_ARRAY(uint8_t, H, LedsPer);
881
882 ✗ memset(V, 0, LedsPer);
883 ✗ memset(H, 0, LedsPer);
884
885 ✗ fill_raw_noise16into8(V, LedsPer, octaves, x, scale, time);
886 ✗ fill_raw_noise8(H, LedsPer, hue_octaves, hue_x, hue_scale, time);
887
888 ✗ for (int i = 0; i < LedsPer; ++i) {
889 ✗ leds[i + j] = CHSV(H[i] + hue_shift, 255, V[i]);
890 }
891 ✗ }
892 }
893
894 ✗ void fill_2dnoise8(CRGB *leds, int width, int height, bool serpentine,
895 uint8_t octaves, uint16_t x, int xscale, uint16_t y, int yscale, uint16_t time,
896 uint8_t hue_octaves, uint16_t hue_x, int hue_xscale, uint16_t hue_y, uint16_t hue_yscale,uint16_t hue_time,bool blend) {
897 ✗ const size_t array_size = (size_t)height * width;
898 ✗ if (array_size <= 0) return;
899 ✗ FASTLED_STACK_ARRAY(uint8_t, V, array_size);
900 ✗ FASTLED_STACK_ARRAY(uint8_t, H, array_size);
901
902 ✗ memset(V,0,height*width);
903 ✗ memset(H,0,height*width);
904
905 ✗ fill_raw_2dnoise8((uint8_t*)V,width,height,octaves,x,xscale,y,yscale,time);
906 ✗ fill_raw_2dnoise8((uint8_t*)H,width,height,hue_octaves,hue_x,hue_xscale,hue_y,hue_yscale,hue_time);
907
908 ✗ int w1 = width-1;
909 ✗ int h1 = height-1;
910 ✗ for(int i = 0; i < height; ++i) {
911 ✗ int wb = i*width;
912 ✗ for(int j = 0; j < width; ++j) {
913 ✗ CRGB led(CHSV(H[(h1-i)*width + (w1-j)], 255, V[i*width + j]));
914
915 ✗ int pos = j;
916 ✗ if(serpentine && (i & 0x1)) {
917 ✗ pos = w1-j;
918 }
919
920 ✗ if(blend) {
921 // Safer blending to avoid potential undefined behavior
922 ✗ CRGB temp = leds[wb+pos];
923 ✗ temp.nscale8(128); // Scale by 50%
924 ✗ led.nscale8(128);
925 ✗ leds[wb+pos] = temp + led;
926 } else {
927 ✗ leds[wb+pos] = led;
928 }
929 }
930 }
931 ✗ }
932
933
934 ✗ void fill_2dnoise16(CRGB *leds, int width, int height, bool serpentine,
935 uint8_t octaves, uint32_t x, int xscale, uint32_t y, int yscale, uint32_t time,
936 uint8_t hue_octaves, uint16_t hue_x, int hue_xscale, uint16_t hue_y, uint16_t hue_yscale,uint16_t hue_time, bool blend, uint16_t hue_shift) {
937
938 ✗ FASTLED_STACK_ARRAY(uint8_t, V, height*width);
939 ✗ FASTLED_STACK_ARRAY(uint8_t, H, height*width);
940
941 ✗ memset(V,0,height*width);
942 ✗ memset(H,0,height*width);
943
944 ✗ fill_raw_2dnoise16into8((uint8_t*)V,width,height,octaves,q44(2,0),171,1,x,xscale,y,yscale,time);
945 // fill_raw_2dnoise16into8((uint8_t*)V,width,height,octaves,x,xscale,y,yscale,time);
946 // fill_raw_2dnoise8((uint8_t*)V,width,height,hue_octaves,x,xscale,y,yscale,time);
947 ✗ fill_raw_2dnoise8((uint8_t*)H,width,height,hue_octaves,hue_x,hue_xscale,hue_y,hue_yscale,hue_time);
948
949
950 ✗ int w1 = width-1;
951 ✗ int h1 = height-1;
952 ✗ hue_shift >>= 8;
953
954 ✗ for(int i = 0; i < height; ++i) {
955 ✗ int wb = i*width;
956 ✗ for(int j = 0; j < width; ++j) {
957 ✗ CRGB led(CHSV(hue_shift + (H[(h1-i)*width + (w1-j)]), 196, V[i*width + j]));
958
959 ✗ int pos = j;
960 ✗ if(serpentine && (i & 0x1)) {
961 ✗ pos = w1-j;
962 }
963
964 ✗ if(blend) {
965 ✗ leds[wb+pos] >>= 1; leds[wb+pos] += (led>>=1);
966 } else {
967 ✗ leds[wb+pos] = led;
968 }
969 }
970 }
971 ✗ }
972
973 FASTLED_NAMESPACE_END
974
975 #pragma GCC diagnostic pop
976