| 190 | } |
| 191 | |
| 192 | static fl::i8 inline __attribute__((always_inline)) grad8(fl::u8 hash, fl::i8 x, fl::i8 y, fl::i8 z) { |
| 193 | // Industry-standard 3D Perlin noise gradient implementation |
| 194 | // Uses proper 12 edge vectors of a cube for maximum range coverage |
| 195 | |
| 196 | switch(hash & 0xF) { |
| 197 | case 0: return fl::avg7( x, y); // (1,1,0) |
| 198 | case 1: return fl::avg7(-x, y); // (-1,1,0) |
| 199 | case 2: return fl::avg7( x, -y); // (1,-1,0) |
| 200 | case 3: return fl::avg7(-x, -y); // (-1,-1,0) |
| 201 | case 4: return fl::avg7( x, z); // (1,0,1) |
| 202 | case 5: return fl::avg7(-x, z); // (-1,0,1) |
| 203 | case 6: return fl::avg7( x, -z); // (1,0,-1) |
| 204 | case 7: return fl::avg7(-x, -z); // (-1,0,-1) |
| 205 | case 8: return fl::avg7( y, z); // (0,1,1) |
| 206 | case 9: return fl::avg7(-y, z); // (0,-1,1) |
| 207 | case 10: return fl::avg7( y, -z); // (0,1,-1) |
| 208 | case 11: return fl::avg7(-y, -z); // (0,-1,-1) |
| 209 | // Repeat first 4 for hash values 12-15 (proper wrap-around) |
| 210 | case 12: return fl::avg7( x, y); // (1,1,0) |
| 211 | case 13: return fl::avg7(-x, y); // (-1,1,0) |
| 212 | case 14: return fl::avg7( x, -y); // (1,-1,0) |
| 213 | case 15: return fl::avg7(-x, -y); // (-1,-1,0) |
| 214 | } |
| 215 | return 0; // Should never reach here |
| 216 | } |
| 217 | |
| 218 | static fl::i8 inline __attribute__((always_inline)) grad8(fl::u8 hash, fl::i8 x, fl::i8 y) |
| 219 | { |