pchestna

Perlin/simplex noise (Spark)

Mar 25th, 2015
505
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 11.38 KB | None | 0 0
  1. // This #include statement was automatically added by the Spark IDE.
  2. #include "FastLED/FastLED.h"
  3. FASTLED_USING_NAMESPACE;
  4.  
  5. #define LED_PIN     D0
  6. #define BRIGHTNESS  64
  7. #define LED_TYPE    WS2812B
  8. #define COLOR_ORDER GRB
  9.  
  10. const uint8_t kCubeSize = 8;
  11. const bool    kMatrixSerpentineLayout = false;
  12.  
  13. typedef enum {X_LAYER, Y_LAYER, Z_LAYER} LAYER;
  14. typedef enum {UP, DOWN} DIRECTION;
  15. bool bAnimate = false;
  16.  
  17. // Dictates the direction of the frames
  18. DIRECTION fillDirection = UP;
  19. // Which axis are we filling the frames
  20. LAYER layer = Y_LAYER;
  21. // Which frame number gets the new noise data
  22. int nFillFrame;
  23.  
  24. #define NUM_LEDS (kCubeSize * kCubeSize * kCubeSize)
  25. #define MAX_DIMENSION kCubeSize
  26.  
  27. // The leds
  28. CRGB leds[NUM_LEDS];
  29.  
  30. // The 16 bit version of our coordinates
  31. static uint16_t x;
  32. static uint16_t y;
  33. static uint16_t z;
  34.  
  35. // This example combines two features of FastLED to produce a remarkable range of
  36. // effects from a relatively small amount of code.  This example combines FastLED's
  37. // color palette lookup functions with FastLED's Perlin/simplex noise generator, and
  38. // the combination is extremely powerful.
  39. //
  40. // You might want to look at the "ColorPalette" and "Noise" examples separately
  41. // if this example code seems daunting.
  42. //
  43. // The basic setup here is that for each frame, we generate a new array of
  44. // 'noise' data, and then map it onto the LED matrix through a color palette.
  45. //
  46. // Periodically, the color palette is changed, and new noise-generation parameters
  47. // are chosen at the same time.  In this example, specific noise-generation
  48. // values have been selected to match the given color palettes; some are faster,
  49. // or slower, or larger, or smaller than others, but there's no reason these
  50. // parameters can't be freely mixed-and-matched.
  51. //
  52. // In addition, this example includes some fast automatic 'data smoothing' at
  53. // lower noise speeds to help produce smoother animations in those cases.
  54. //
  55. // The FastLED built-in color palettes (Forest, Clouds, Lava, Ocean, Party) are
  56. // used, as well as some 'hand-defined' ones, and some proceedurally generated
  57. // palettes.
  58.  
  59. // We're using the x/y dimensions to map to the x/y pixels on the matrix.  We'll
  60. // use the z-axis for "time".  speed determines how fast time moves forward.  Try
  61. // 1 for a very slow moving effect, or 60 for something that ends up looking like
  62. // water.
  63. uint16_t speed = 1; // speed is set dynamically once we've started up
  64.  
  65. // Scale determines how far apart the pixels in our noise matrix are.  Try
  66. // changing these values around to see how it affects the motion of the display.  The
  67. // higher the value of scale, the more "zoomed out" the noise will be.  A value
  68. // of 1 will be so zoomed in, you'll mostly see solid colors.
  69. uint16_t scale = 30; // scale is set dynamically once we've started up
  70.  
  71. // This is the array that we keep our computed noise values in
  72. uint8_t noise[MAX_DIMENSION][MAX_DIMENSION];
  73.  
  74. CRGBPalette16 currentPalette( LavaColors_p );
  75. uint8_t       colorLoop = 1;
  76.  
  77. void setup() {
  78.   delay(3000);
  79.   LEDS.addLeds<LED_TYPE,LED_PIN,COLOR_ORDER>(leds,NUM_LEDS);
  80.   LEDS.setBrightness(BRIGHTNESS);
  81.  
  82.   // Initialize our coordinates to some random values
  83.   x = random16();
  84.   y = random16();
  85.   z = random16();
  86.  
  87.   if (fillDirection == UP) nFillFrame = 0; else nFillFrame = kCubeSize-1;
  88. }
  89.  
  90. // Fill a frame of the x/y array of 8-bit noise values using the inoise8 function.
  91. void fillnoise8() {
  92.   // If we're runing at a low "speed", some 8-bit artifacts become visible
  93.   // from frame-to-frame.  In order to reduce this, we can do some fast data-smoothing.
  94.   // The amount of data smoothing we're doing depends on "speed".
  95.   uint8_t dataSmoothing = 0;
  96.   if( speed < 50) {
  97.     dataSmoothing = 200 - (speed * 4);
  98.   }
  99.  
  100.   for(int i = 0; i < MAX_DIMENSION; i++) {
  101.     int ioffset = scale * i;
  102.     for(int j = 0; j < MAX_DIMENSION; j++) {
  103.       int joffset = scale * j;
  104.      
  105.       uint8_t data = inoise8(x + ioffset,y + joffset,z);
  106.  
  107.       // The range of the inoise8 function is roughly 16-238.
  108.       // These two operations expand those values out to roughly 0..255
  109.       // You can comment them out if you want the raw noise data.
  110.       data = qsub8(data,16);
  111.       data = qadd8(data,scale8(data,39));
  112.  
  113.       if( dataSmoothing ) {
  114.         uint8_t olddata = noise[i][j];
  115.         uint8_t newdata = scale8( olddata, dataSmoothing) + scale8( data, 256 - dataSmoothing);
  116.         data = newdata;
  117.       }
  118.      
  119.       noise[i][j] = data;
  120.     }
  121.   }
  122.  
  123.   z += speed;
  124.  
  125.   // apply slow drift to X and Y, just for visual variation.
  126.   x += speed / 8;
  127.   y -= speed / 16;
  128. }
  129.  
  130. void mapNoiseToLEDsUsingPalette()
  131. {
  132.   static uint8_t ihue=0;
  133.  
  134.   for(int i = 0; i < kCubeSize; i++) {
  135.     for(int j = 0; j < kCubeSize; j++) {
  136.       // We use the value at the (i,j) coordinate in the noise
  137.       // array for our brightness, and the flipped value from (j,i)
  138.       // for our pixel's index into the color palette.
  139.  
  140.       uint8_t index = noise[j][i];
  141.       uint8_t bri =   noise[i][j];
  142.  
  143.       // if this palette is a 'loop', add a slowly-changing base value
  144.       if( colorLoop) {
  145.         index += ihue;
  146.       }
  147.  
  148.       // brighten up, as the color palette itself often contains the
  149.       // light/dark dynamic range desired
  150.       if( bri > 127 ) {
  151.         bri = 255;
  152.       } else {
  153.         bri = dim8_raw( bri * 2);
  154.       }
  155.  
  156.       CRGB color = ColorFromPalette( currentPalette, index, bri);
  157.      
  158.       static int nTo;
  159.       switch (layer)
  160.       {
  161.          case X_LAYER:
  162.            nTo = XYZ(nFillFrame, i, j);
  163.          break;
  164.          case Y_LAYER:
  165.            nTo = XYZ(i, nFillFrame, j);
  166.          break;
  167.          case Z_LAYER:
  168.            nTo = XYZ(i, j, nFillFrame);
  169.          break;
  170.       }
  171.       leds[nTo] = color;
  172.     }
  173.   }
  174.  
  175.   ihue+=1;
  176. }
  177.  
  178. // Copies pixels from one layer to another
  179. void copyLayer(uint8_t fromLayer, uint8_t toLayer);
  180. void copyLayer(uint8_t fromLayer, uint8_t toLayer)
  181. {
  182.   int nFrom; // from pixel
  183.   int nTo; // to pixel
  184.  
  185.   for (int m = 0; m < kCubeSize; m++)
  186.     for (int n = 0; n < kCubeSize; n++)
  187.     {
  188.       switch (layer)
  189.       {
  190.          case X_LAYER:
  191.            nFrom = XYZ(fromLayer, m, n);
  192.            nTo = XYZ(toLayer, m, n);
  193.          break;
  194.          case Y_LAYER:
  195.            nFrom = XYZ(m, fromLayer, n);
  196.            nTo = XYZ(m, toLayer, n);
  197.          break;
  198.          case Z_LAYER:
  199.            nFrom = XYZ(m, n, fromLayer);
  200.            nTo = XYZ(m, n, toLayer);
  201.          break;
  202.       }
  203.       leds[nTo] = leds[nFrom];
  204.     }
  205. }
  206.  
  207. // Copy frames foward in the plane being used from the fillFrame back
  208. void moveFrameForward()
  209. {
  210.   switch (fillDirection)
  211.   {
  212.     case UP:
  213.     {
  214.       for (int nLayer = kCubeSize-1; nLayer > 0; nLayer--)
  215.       {
  216.         if (bAnimate)
  217.           copyLayer(nLayer-1, nLayer);
  218.         else
  219.           copyLayer(nFillFrame, nLayer);
  220.       }
  221.     }
  222.     break;
  223.    
  224.     case DOWN:
  225.     {
  226.       for (int nLayer = 0; nLayer < kCubeSize; nLayer++)
  227.       {
  228.         if (bAnimate)
  229.           copyLayer(nLayer+1, nLayer);
  230.         else
  231.           copyLayer(nFillFrame, nLayer);
  232.       }
  233.     }
  234.     break;
  235.   }
  236. }
  237.  
  238. void loop() {
  239.   // Periodically choose a new palette, speed, and scale
  240.   ChangePaletteAndSettingsPeriodically();
  241.  
  242.   // generate noise data
  243.   fillnoise8();
  244.  
  245.   // convert the noise data to colors in the LED array
  246.   // using the current palette
  247.   mapNoiseToLEDsUsingPalette();
  248.  
  249.   if (bAnimate)
  250.   {
  251.     LEDS.show();
  252.     delay(10);
  253.     // Copy frames
  254.     moveFrameForward();
  255.   }
  256.   else // mirror to other frames
  257.   {
  258.     moveFrameForward();
  259.     LEDS.show();
  260.     delay(10);
  261.   }
  262. }
  263.  
  264.  
  265.  
  266. // There are several different palettes of colors demonstrated here.
  267. //
  268. // FastLED provides several 'preset' palettes: RainbowColors_p, RainbowStripeColors_p,
  269. // OceanColors_p, CloudColors_p, LavaColors_p, ForestColors_p, and PartyColors_p.
  270. //
  271. // Additionally, you can manually define your own color palettes, or you can write
  272. // code that creates color palettes on the fly.
  273.  
  274. // 1 = 5 sec per palette
  275. // 2 = 10 sec per palette
  276. // etc
  277. #define HOLD_PALETTES_X_TIMES_AS_LONG 5
  278.  
  279. void ChangePaletteAndSettingsPeriodically()
  280. {
  281.   uint8_t secondHand = ((millis() / 1000) / HOLD_PALETTES_X_TIMES_AS_LONG) % 60;
  282.   static uint8_t lastSecond = 99;
  283.  
  284.   if( lastSecond != secondHand) {
  285.     lastSecond = secondHand;
  286.     if( secondHand ==  0)  { currentPalette = RainbowColors_p;         speed = 1; scale = 30; colorLoop = 1; }
  287.     if( secondHand ==  5)  { SetupPurpleAndGreenPalette();             speed = 1; scale = 50; colorLoop = 1; }
  288.     if( secondHand == 10)  { SetupBlackAndWhiteStripedPalette();       speed = 1; scale = 30; colorLoop = 1; }
  289.     if( secondHand == 15)  { currentPalette = ForestColors_p;          speed = 1; scale =120; colorLoop = 0; }
  290.     if( secondHand == 20)  { currentPalette = CloudColors_p;           speed = 1; scale = 30; colorLoop = 0; }
  291.     if( secondHand == 25)  { currentPalette = LavaColors_p;            speed = 1; scale = 50; colorLoop = 0; }
  292.     if( secondHand == 30)  { currentPalette = OceanColors_p;           speed = 1; scale = 90; colorLoop = 0; }
  293.     if( secondHand == 35)  { currentPalette = PartyColors_p;           speed = 1; scale = 30; colorLoop = 1; }
  294.     if( secondHand == 40)  { SetupRandomPalette();                     speed = 1; scale = 20; colorLoop = 1; }
  295.     if( secondHand == 45)  { SetupRandomPalette();                     speed = 1; scale = 50; colorLoop = 1; }
  296.     if( secondHand == 50)  { SetupRandomPalette();                     speed = 1; scale = 90; colorLoop = 1; }
  297.     if( secondHand == 55)  { currentPalette = RainbowStripeColors_p;   speed = 1; scale = 20; colorLoop = 1; }
  298.   }
  299. }
  300.  
  301. // This function generates a random palette that's a gradient
  302. // between four different colors.  The first is a dim hue, the second is
  303. // a bright hue, the third is a bright pastel, and the last is
  304. // another bright hue.  This gives some visual bright/dark variation
  305. // which is more interesting than just a gradient of different hues.
  306. void SetupRandomPalette()
  307. {
  308.   currentPalette = CRGBPalette16(
  309.                       CHSV( random8(), 255, 32),
  310.                       CHSV( random8(), 255, 255),
  311.                       CHSV( random8(), 128, 255),
  312.                       CHSV( random8(), 255, 255));
  313. }
  314.  
  315. // This function sets up a palette of black and white stripes,
  316. // using code.  Since the palette is effectively an array of
  317. // sixteen CRGB colors, the various fill_* functions can be used
  318. // to set them up.
  319. void SetupBlackAndWhiteStripedPalette()
  320. {
  321.   // 'black out' all 16 palette entries...
  322.   fill_solid( currentPalette, 16, CRGB::Black);
  323.   // and set every fourth one to white.
  324.   currentPalette[0] = CRGB::White;
  325.   currentPalette[4] = CRGB::White;
  326.   currentPalette[8] = CRGB::White;
  327.   currentPalette[12] = CRGB::White;
  328.  
  329. }
  330.  
  331. // This function sets up a palette of purple and green stripes.
  332. void SetupPurpleAndGreenPalette()
  333. {
  334.   CRGB purple = CHSV( HUE_PURPLE, 255, 255);
  335.   CRGB green  = CHSV( HUE_GREEN, 255, 255);
  336.   CRGB black  = CRGB::Black;
  337.  
  338.   currentPalette = CRGBPalette16(
  339.     green,  green,  black,  black,
  340.     purple, purple, black,  black,
  341.     green,  green,  black,  black,
  342.     purple, purple, black,  black );
  343. }
  344.  
  345. //
  346. // xyz coordinate mapping code
  347. //
  348. uint16_t XYZ( uint8_t x, uint8_t y, uint8_t z)
  349. {
  350.   uint16_t i;
  351.  
  352.   i = 8 * ((y * kCubeSize) + x) + z;
  353.  
  354.   if ((i >= 0) && (i <= 512))
  355.     return i;
  356.   else
  357.     return 0;
  358. }
Advertisement
Add Comment
Please, Sign In to add comment