// Based on Hugo elias 2d water in c++
// Super Thank: @Sutaburosu (2D water Ripple on reddit)
#include <FastLED.h>
#define WIDTH 32
#define HEIGHT 32
#define NUM_LEDS ((WIDTH) * (HEIGHT))
CRGB leds[NUM_LEDS];
#define WATERWIDTH (WIDTH + 2)
#define WATERHEIGHT (HEIGHT + 2)
uint8_t water[2][WATERWIDTH * WATERHEIGHT];
uint8_t center_x = 12; // Set the X coordinate for the center
uint8_t center_y = 12; // Set the Y coordinate for the center
int period = 1000;
int period2 = 1000;
int period3 = 1200;
unsigned long time_now = 1;
unsigned long time_now2 = 1;
unsigned long time_now3 = 1;
void setup() {
//Serial.begin(115200);
FastLED.addLeds<NEOPIXEL, 2>(leds, NUM_LEDS);
}
uint16_t XY(uint8_t x, uint8_t y) {
if (y & 1)
return (y + 1) * WIDTH - x - 1;
return y * WIDTH + x;
}
void loop() {
// swap the src/dest buffers on each frame
static uint8_t buffer = 0;
uint8_t * const bufA = &water[buffer][0];
buffer = (buffer + 1) % 2;
uint8_t * const bufB = &water[buffer][0];
//add a moving stimulus
if(millis() >= time_now + period){
time_now += period;
center_y = 0;
center_x = 0;
}
if(millis() >= time_now2 + period2){
time_now2 += period2;
center_y = random(1,32);
center_x = random(1,32);
}
if(millis() >= time_now3 + period3){
time_now3 += period3;
center_y = random(1,32);
center_x = random(1,32);
}
wu_water(bufA, center_x * 256, center_y * 256, beatsin8(160, 64, 255));
// animate the water
process_water(bufA, bufB);
// display the water effect on the LEDs
uint8_t * input = bufB + WATERWIDTH - 1;
static uint16_t pal_offset = 0;
pal_offset += 1;
for (uint8_t y = 0; y < HEIGHT; y++) {
input += 2;
for (uint8_t x = 0; x < WIDTH; x++) {
leds[XY(x, y)] = CHSV(x/2 * y+1/2 + (*input++ << 8), 255, *input * 7);
}
}
FastLED.show();
}
void process_water(uint8_t * src, uint8_t * dst) {
src += WATERWIDTH - 1;
dst += WATERWIDTH - 1;
for (uint8_t y = 1; y < WATERHEIGHT - 1; y++) {
src += 2; dst += 2;
for (uint8_t x = 1; x < WATERWIDTH - 1; x++) {
uint16_t t = src[-1] + src[1] + src[-WATERWIDTH] + src[WATERWIDTH];
t >>= 1;
if (dst[0] < t)
dst[0] = t - dst[0];
else
dst[0] = 0;
dst[0] -= dst[0] >> 6;
src++; dst++;
}
}
}
/*
void wu_water(uint8_t * const buf, uint16_t x, uint16_t y, uint8_t bright) {
// extract the fractional parts and derive their inverses
uint8_t xx = x & 0xff, yy = y & 0xff, ix = 255 - xx, iy = 255 - yy;
// calculate the intensities for each affected pixel
#define WU_WEIGHT(a, b) ((uint8_t)(((a) * (b) + (a) + (b)) >> 8))
uint8_t wu[4] = {WU_WEIGHT(ix, iy), WU_WEIGHT(xx, iy),
WU_WEIGHT(ix, yy), WU_WEIGHT(xx, yy)
};
#undef WU_WEIGHT
// multiply the intensities by the colour, and saturating-add them to the pixels
for (uint8_t i = 0; i < 4; i++) {
uint8_t local_x = (x >> 8) + (i & 1);
uint8_t local_y = (y >> 8) + ((i >> 1) & 1);
uint16_t xy = WATERWIDTH * local_y + local_x;
if (xy >= WATERWIDTH * WATERHEIGHT) continue;
uint16_t this_bright = bright * wu[i];
buf[xy] = qadd8(buf[xy], this_bright >> 8);
}
}
*/
void wu_water(uint8_t * const buf, uint16_t x, uint16_t y, uint8_t bright) {
// extract the fractional parts and derive their inverses
uint8_t xx = x & 0xff, yy = y & 0xff, ix = 255 - xx, iy = 255 - yy;
// calculate the intensities for each affected pixel
uint8_t wu[4] = {
(ix * iy) >> 9, // Top-left
(xx * iy) >> 9, // Top-right
(ix * yy) >> 9, // Bottom-left
(xx * yy) >> 9 // Bottom-right
};
for (uint8_t i = 0; i < 4; i++) {
uint8_t local_x = (x >> 8) + (i & 1);
uint8_t local_y = (y >> 8) + ((i >> 1) & 1);
uint16_t xy = WATERWIDTH * local_y + local_x;
if (xy >= WATERWIDTH * WATERHEIGHT) continue;
uint16_t this_bright = bright * wu[i];
buf[xy] = qadd8(buf[xy], this_bright);
}
}FPS: 0
Power: 0.00W
Power: 0.00W