| 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 |