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