effects.h
  1  // SPDX-FileCopyrightText: 2019 Anne Barela for Adafruit Industries
  2  //
  3  // SPDX-License-Identifier: MIT
  4  
  5  //   Selection of effects from the FastLED library & Macetech RGB Shades
  6  
  7  
  8  //  Triple Sine Waves
  9  void threeSine() {
 10  
 11    static byte sineOffset = 0; // counter for current position of sine waves
 12  
 13    // startup tasks
 14    if (effectInit == false) {
 15      effectInit = true;
 16      effectDelay = 20;
 17    }
 18  
 19    // Draw one frame of the animation into the LED array
 20    for (byte x = 0; x < kMatrixWidth; x++) {
 21      for (int y = 0; y < kMatrixHeight; y++) {
 22  
 23        // Calculate "sine" waves with varying periods
 24        // sin8 is used for speed; cos8, quadwave8, or triwave8 would also work here
 25        byte sinDistanceR = qmul8(abs(y * (255 / kMatrixHeight) - sin8(sineOffset * 9 + x * 16)), 2);
 26        byte sinDistanceG = qmul8(abs(y * (255 / kMatrixHeight) - sin8(sineOffset * 10 + x * 16)), 2);
 27        byte sinDistanceB = qmul8(abs(y * (255 / kMatrixHeight) - sin8(sineOffset * 11 + x * 16)), 2);
 28  
 29        leds[XY(x, y)] = CRGB(255 - sinDistanceR, 255 - sinDistanceG, 255 - sinDistanceB);
 30      }
 31    }
 32  
 33    sineOffset++; // byte will wrap from 255 to 0, matching sin8 0-255 cycle
 34  
 35  }
 36  
 37  
 38  
 39  //  Solid Colors
 40  //  Create your own!
 41  void SolidWhite() //for the porto-potty
 42  {
 43      fill_solid( leds, NUM_LEDS, CRGB::White);
 44  }
 45  
 46  void SolidRed() //for startup, good for saving battery
 47  {
 48      fill_solid( leds, NUM_LEDS, CRGB::Red);
 49  }
 50  
 51  
 52  
 53  //  RGB Plasma
 54  void plasma() {
 55  
 56    static byte offset  = 0; // counter for radial color wave motion
 57    static int plasVector = 0; // counter for orbiting plasma center
 58  
 59    // startup tasks
 60    if (effectInit == false) {
 61      effectInit = true;
 62      effectDelay = 10;
 63    }
 64  
 65    // Calculate current center of plasma pattern (can be offscreen)
 66    int xOffset = cos8(plasVector / 256);
 67    int yOffset = sin8(plasVector / 256);
 68  
 69    // Draw one frame of the animation into the LED array
 70    for (int x = 0; x < kMatrixWidth; x++) {
 71      for (int y = 0; y < kMatrixHeight; y++) {
 72        byte color = sin8(sqrt(sq(((float)x - 7.5) * 10 + xOffset - 127) + sq(((float)y - 2) * 10 + yOffset - 127)) + offset);
 73        leds[XY(x, y)] = CHSV(color, 255, 255);
 74      }
 75    }
 76  
 77    offset++; // wraps at 255 for sin8
 78    plasVector += 16; // using an int for slower orbit (wraps at 65536)
 79  
 80  }
 81  
 82  
 83  
 84  // Scanning pattern left/right, using global hue cycle
 85  void rider() {
 86  
 87    static byte riderPos = 0;
 88  
 89    // startup tasks
 90    if (effectInit == false) {
 91      effectInit = true;
 92      effectDelay = 5;
 93      riderPos = 0;
 94    }
 95  
 96    // Draw one frame of the animation into the LED array
 97    for (byte x = 0; x < kMatrixWidth; x++) {
 98      int brightness = abs(x * (256 / kMatrixWidth) - triwave8(riderPos) * 2 + 127) * 3;
 99      if (brightness > 255) brightness = 255;
100      brightness = 255 - brightness;
101      CRGB riderColor = CHSV(cycleHue, 255, brightness);
102      for (byte y = 0; y < kMatrixHeight; y++) {
103        leds[XY(x, y)] = riderColor;
104      }
105    }
106  
107    riderPos++; // byte wraps to 0 at 255, triwave8 is also 0-255 periodic
108  
109  }
110  
111  
112  
113  // Fills saturated colors into the array from alternating directions
114  void colorFill() {
115  
116    static byte currentColor = 0;
117    static byte currentRow = 0;
118    static byte currentDirection = 0;
119  
120    // startup tasks
121    if (effectInit == false) {
122      effectInit = true;
123      effectDelay = 45;
124      currentColor = 0;
125      currentRow = 0;
126      currentDirection = 0;
127      currentPalette = RainbowColors_p;
128    }
129  
130    // test a bitmask to fill up or down when currentDirection is 0 or 2 (0b00 or 0b10)
131    if (!(currentDirection & 1)) {
132      effectDelay = 45; // slower since vertical has fewer pixels
133      for (byte x = 0; x < kMatrixWidth; x++) {
134        byte y = currentRow;
135        if (currentDirection == 2) y = kMatrixHeight - 1 - currentRow;
136        leds[XY(x, y)] = currentPalette[currentColor];
137      }
138    }
139  
140    // test a bitmask to fill left or right when currentDirection is 1 or 3 (0b01 or 0b11)
141    if (currentDirection & 1) {
142      effectDelay = 20; // faster since horizontal has more pixels
143      for (byte y = 0; y < kMatrixHeight; y++) {
144        byte x = currentRow;
145        if (currentDirection == 3) x = kMatrixWidth - 1 - currentRow;
146        leds[XY(x, y)] = currentPalette[currentColor];
147      }
148    }
149  
150    currentRow++;
151  
152    // detect when a fill is complete, change color and direction
153    if ((!(currentDirection & 1) && currentRow >= kMatrixHeight) || ((currentDirection & 1) && currentRow >= kMatrixWidth)) {
154      currentRow = 0;
155      currentColor += random8(3, 6);
156      if (currentColor > 15) currentColor -= 16;
157      currentDirection++;
158      if (currentDirection > 3) currentDirection = 0;
159      effectDelay = 300; // wait a little bit longer after completing a fill
160    }
161  }
162  
163  
164  
165  // Random pixels scroll sideways, using current hue
166  #define rainDir 0
167  void sideRain() {
168  
169    // startup tasks
170    if (effectInit == false) {
171      effectInit = true;
172      effectDelay = 30;
173    }
174  
175    scrollArray(rainDir);
176    byte randPixel = random8(kMatrixHeight);
177    for (byte y = 0; y < kMatrixHeight; y++) leds[XY((kMatrixWidth - 1) * rainDir, y)] = CRGB::Black;
178    leds[XY((kMatrixWidth - 1)*rainDir, randPixel)] = CHSV(cycleHue, 255, 255);
179  
180  }
181  
182  
183  
184  //  CONFETTI: pixels with random locations and random colors selected from a palette
185  //  Create your own confetti modes using the built in Palettes (see utils.h) or create your own
186  //  Use with the fadeAll function (see .ino) to allow old pixels to decay
187  void confetti() {
188    // startup tasks
189    if (effectInit == false) {
190      effectInit = true;
191      effectDelay = 10;
192      selectRandomPalette();
193    }
194  
195    // scatter random colored pixels at several random coordinates
196    for (byte i = 0; i < 4; i++) {
197      leds[XY(random16(kMatrixWidth), random16(kMatrixHeight))] = ColorFromPalette(currentPalette, random16(255), 255); //CHSV(random16(255), 255, 255);
198      random16_add_entropy(1);
199    }
200  }
201  
202  //Palette for myConfetti
203  const TProgmemPalette16 MyColors_p PROGMEM =
204  {
205    CRGB:: Crimson,
206    CRGB:: Maroon,
207    CRGB:: Red,
208    CRGB:: OrangeRed,
209   
210    CRGB:: Crimson,
211    CRGB:: Maroon,
212    CRGB:: Red,
213    CRGB:: OrangeRed,
214   
215    CRGB:: Crimson,
216    CRGB:: Maroon,
217    CRGB:: Red,
218    CRGB:: OrangeRed,
219   
220    CRGB:: Crimson,
221    CRGB:: Maroon,
222    CRGB:: Red,
223    CRGB:: OrangeRed,
224  };
225  
226  void myConfetti() {
227    // startup tasks
228    if (effectInit == false) {
229      effectInit = true;
230      effectDelay = 15;
231    }
232  
233  
234  //  scatter random colored pixels at several random coordinates
235    for (byte i = 0; i < 4; i++) {
236      leds[XY(random16(kMatrixWidth), random16(kMatrixHeight))] = ColorFromPalette(MyColors_p, random16(255), 255); //CHSV(random16(255), 255, 255);
237      random16_add_entropy(1);
238    }
239  
240  }
241  
242  
243  //  Example from the NoisePlusPalette FastLED example sketch. See utils.h
244  void NoisePlusPalette() {
245    
246    fillnoise8();
247    
248    mapNoiseToLEDsUsingPalette();
249  
250  }
251  
252  
253  //  Draw slanting bars scrolling across the array, using current hue
254  void slantBars() {
255  
256    static byte slantPos = 0;
257  
258    // startup tasks
259    if (effectInit == false) {
260      effectInit = true;
261      effectDelay = 5;
262    }
263  
264    for (byte x = 0; x < kMatrixWidth; x++) {
265      for (byte y = 0; y < kMatrixHeight; y++) {
266        leds[XY(x, y)] = CHSV(cycleHue, 255, quadwave8(x * 32 + y * 32 + slantPos));
267      }
268    }
269  
270    slantPos -= 4;
271  
272  }
273  
274  
275  //from Mark Kriegsman
276  void swirly()
277  {
278    // startup tasks
279    if (effectInit == false) {
280      effectInit = true;
281      effectDelay = 15;
282    }
283  
284    // Apply some blurring to whatever's already on the matrix
285    // Note that we never actually clear the matrix, we just constantly
286    // blur it repeatedly.  Since the blurring is 'lossy', there's
287    // an automatic trend toward black -- by design.
288    uint8_t blurAmount = beatsin8(2,10,255);
289    blur2d( leds, kMatrixWidth, kMatrixHeight, blurAmount);
290  
291    // Use two out-of-sync sine waves
292    uint8_t  i = beatsin8( 27, kBorderWidth, kMatrixHeight-kBorderWidth);
293    uint8_t  j = beatsin8( 41, kBorderWidth, kMatrixWidth-kBorderWidth);
294    // Also calculate some reflections
295    uint8_t ni = (kMatrixWidth-1)-i;
296    uint8_t nj = (kMatrixWidth-1)-j;
297    
298    // The color of each point shifts over time, each at a different speed.
299    uint16_t ms = millis();  
300    leds[XY( i, j)] += CHSV( ms / 11, 200, 255);
301    leds[XY( j, i)] += CHSV( ms / 13, 200, 255);
302    leds[XY(ni,nj)] += CHSV( ms / 17, 200, 255);
303    leds[XY(nj,ni)] += CHSV( ms / 29, 200, 255);
304    leds[XY( i,nj)] += CHSV( ms / 37, 200, 255);
305    leds[XY(ni, j)] += CHSV( ms / 41, 200, 255);
306    
307    FastLED.show();
308  }