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