FastLED 3.9.7
Loading...
Searching...
No Matches
Water.ino
1// Author: sutaburosu
2
3// based on https://web.archive.org/web/20160418004149/http://freespace.virgin.net/hugo.elias/graphics/x_water.htm
4
5#include <FastLED.h>
6#include "Arduino.h"
7#include "fl/xymap.h"
8
9using namespace fl;
10
11#define WIDTH 32
12#define HEIGHT 32
13#define NUM_LEDS ((WIDTH) * (HEIGHT))
14CRGB leds[NUM_LEDS];
15
16// the water needs 2 arrays each slightly bigger than the screen
17#define WATERWIDTH (WIDTH + 2)
18#define WATERHEIGHT (HEIGHT + 2)
19uint8_t water[2][WATERWIDTH * WATERHEIGHT];
20
21void wu_water(uint8_t * const buf, uint16_t x, uint16_t y, uint8_t bright);
22void process_water(uint8_t * src, uint8_t * dst) ;
23
24void setup() {
25 Serial.begin(115200);
26 FastLED.addLeds<NEOPIXEL, 2>(leds, NUM_LEDS).setScreenMap(WIDTH, HEIGHT);
27}
28
29// from: https://github.com/FastLED/FastLED/pull/202
30CRGB MyColorFromPaletteExtended(const CRGBPalette16& pal, uint16_t index, uint8_t brightness, TBlendType blendType) {
31 // Extract the four most significant bits of the index as a palette index.
32 uint8_t index_4bit = (index >> 12);
33 // Calculate the 8-bit offset from the palette index.
34 uint8_t offset = (uint8_t)(index >> 4);
35 // Get the palette entry from the 4-bit index
36 const CRGB* entry = &(pal[0]) + index_4bit;
37 uint8_t red1 = entry->red;
38 uint8_t green1 = entry->green;
39 uint8_t blue1 = entry->blue;
40
41 uint8_t blend = offset && (blendType != NOBLEND);
42 if (blend) {
43 if (index_4bit == 15) {
44 entry = &(pal[0]);
45 } else {
46 entry++;
47 }
48
49 // Calculate the scaling factor and scaled values for the lower palette value.
50 uint8_t f1 = 255 - offset;
51 red1 = scale8_LEAVING_R1_DIRTY(red1, f1);
52 green1 = scale8_LEAVING_R1_DIRTY(green1, f1);
53 blue1 = scale8_LEAVING_R1_DIRTY(blue1, f1);
54
55 // Calculate the scaled values for the neighbouring palette value.
56 uint8_t red2 = entry->red;
57 uint8_t green2 = entry->green;
58 uint8_t blue2 = entry->blue;
59 red2 = scale8_LEAVING_R1_DIRTY(red2, offset);
60 green2 = scale8_LEAVING_R1_DIRTY(green2, offset);
61 blue2 = scale8_LEAVING_R1_DIRTY(blue2, offset);
62 cleanup_R1();
63
64 // These sums can't overflow, so no qadd8 needed.
65 red1 += red2;
66 green1 += green2;
67 blue1 += blue2;
68 }
69 if (brightness != 255) {
70 // nscale8x3_video(red1, green1, blue1, brightness);
71 nscale8x3(red1, green1, blue1, brightness);
72 }
73 return CRGB(red1, green1, blue1);
74}
75
76// Rectangular grid
77XYMap xyMap(WIDTH, HEIGHT, false);
78
79// map X & Y coordinates onto a horizontal serpentine matrix layout
80uint16_t XY(uint8_t x, uint8_t y) {
81 return xyMap.mapToIndex(x, y);
82}
83
84void loop() {
85 // swap the src/dest buffers on each frame
86 static uint8_t buffer = 0;
87 uint8_t * const bufA = &water[buffer][0];
88 buffer = (buffer + 1) % 2;
89 uint8_t * const bufB = &water[buffer][0];
90
91 // add a moving stimulus
92 wu_water(bufA, beatsin16(13, 256, HEIGHT * 256), beatsin16(7, 256, WIDTH * 256), beatsin8(160, 64, 255));
93
94 // animate the water
95 process_water(bufA, bufB);
96
97
98 // display the water effect on the LEDs
99 uint8_t * input = bufB + WATERWIDTH - 1;
100 static uint16_t pal_offset = 0;
101 pal_offset += 256;
102 for (uint8_t y = 0; y < HEIGHT; y++) {
103 input += 2;
104 for (uint8_t x = 0; x < WIDTH; x++) {
105 leds[XY(x, y)] = MyColorFromPaletteExtended(RainbowColors_p, pal_offset + (*input++ << 8), 255, LINEARBLEND);
106 }
107 }
108 FastLED.show();
109}
110
111void process_water(uint8_t * src, uint8_t * dst) {
112 src += WATERWIDTH - 1;
113 dst += WATERWIDTH - 1;
114 for (uint8_t y = 1; y < WATERHEIGHT - 1; y++) {
115 src += 2; dst += 2;
116 for (uint8_t x = 1; x < WATERWIDTH - 1; x++) {
117 uint16_t t = src[-1] + src[1] + src[-WATERWIDTH] + src[WATERWIDTH];
118 t >>= 1;
119 if (dst[0] < t)
120 dst[0] = t - dst[0];
121 else
122 dst[0] = 0;
123
124 dst[0] -= dst[0] >> 6;
125 src++; dst++;
126 }
127 }
128}
129
130// draw a blob of 4 pixels with their relative brightnesses conveying sub-pixel positioning
131void wu_water(uint8_t * const buf, uint16_t x, uint16_t y, uint8_t bright) {
132 // extract the fractional parts and derive their inverses
133 uint8_t xx = x & 0xff, yy = y & 0xff, ix = 255 - xx, iy = 255 - yy;
134 // calculate the intensities for each affected pixel
135 #define WU_WEIGHT(a, b) ((uint8_t)(((a) * (b) + (a) + (b)) >> 8))
136 uint8_t wu[4] = {WU_WEIGHT(ix, iy), WU_WEIGHT(xx, iy),
137 WU_WEIGHT(ix, yy), WU_WEIGHT(xx, yy)
138 };
139 #undef WU_WEIGHT
140 // multiply the intensities by the colour, and saturating-add them to the pixels
141 for (uint8_t i = 0; i < 4; i++) {
142 uint8_t local_x = (x >> 8) + (i & 1);
143 uint8_t local_y = (y >> 8) + ((i >> 1) & 1);
144 uint16_t xy = WATERWIDTH * local_y + local_x;
145 if (xy >= WATERWIDTH * WATERHEIGHT) continue;
146 uint16_t this_bright = bright * wu[i];
147 buf[xy] = qadd8(buf[xy], this_bright >> 8);
148 }
149}
CFastLED FastLED
Global LED strip management instance.
Definition FastLED.cpp:45
central include file for FastLED, defines the CFastLED class/object
void show(uint8_t scale)
Update all our controllers with the current led colors, using the passed in brightness.
Definition FastLED.cpp:94
static CLEDController & addLeds(CLEDController *pLed, struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset=0)
Add a CLEDController instance to the world.
Definition FastLED.cpp:79
RGB color palette with 16 discrete values.
Definition colorutils.h:997
LED controller for WS2812 LEDs with GRB color order.
Definition FastLED.h:135
LIB8STATIC uint16_t beatsin16(accum88 beats_per_minute, uint16_t lowest=0, uint16_t highest=65535, uint32_t timebase=0, uint16_t phase_offset=0)
Generates a 16-bit sine wave at a given BPM that oscillates within a given range.
Definition lib8tion.h:957
LIB8STATIC uint8_t beatsin8(accum88 beats_per_minute, uint8_t lowest=0, uint8_t highest=255, uint32_t timebase=0, uint8_t phase_offset=0)
Generates an 8-bit sine wave at a given BPM that oscillates within a given range.
Definition lib8tion.h:975
CRGB blend(const CRGB &p1, const CRGB &p2, fract8 amountOfP2)
Computes a new color blended some fraction of the way between two other colors.
LIB8STATIC_ALWAYS_INLINE uint8_t qadd8(uint8_t i, uint8_t j)
Add one byte to another, saturating at 0xFF.
Definition math8.h:31
TBlendType
Color interpolation options for palette.
@ NOBLEND
No interpolation between palette entries.
@ LINEARBLEND
Linear interpolation between palette entries, with wrap-around from end to the beginning again.
const TProgmemRGBPalette16 RainbowColors_p
HSV Rainbow.
LIB8STATIC_ALWAYS_INLINE void cleanup_R1()
Clean up the r1 register after a series of *LEAVING_R1_DIRTY calls.
Definition scale8.h:333
LIB8STATIC_ALWAYS_INLINE uint8_t scale8_LEAVING_R1_DIRTY(uint8_t i, fract8 scale)
This version of scale8() does not clean up the R1 register on AVR.
Definition scale8.h:170
LIB8STATIC void nscale8x3(uint8_t &r, uint8_t &g, uint8_t &b, fract8 scale)
Scale three one-byte values by a fourth one, which is treated as the numerator of a fraction whose de...
Definition scale8.h:357
Implements a simple red square effect for 2D LED grids.
Definition crgb.h:16
Representation of an RGB pixel (Red, Green, Blue)
Definition crgb.h:54
uint8_t red
Red channel value.
Definition crgb.h:59
uint8_t blue
Blue channel value.
Definition crgb.h:67
uint8_t green
Green channel value.
Definition crgb.h:63