// https://www.reddit.com/r/FastLED/comments/1jw7t7s/help_getting_started_with_an_effect_i_want/
// this doesn't work; it needs to be a build define instead
#define MAX_CLED_CONTROLLERS 20
#include <FastLED.h>
const int xSize = 5;
const int ySize = 4;
const float tau = 6.2831853072;
CHSV colours[xSize * ySize];
CRGBArray<xSize * ySize * 40> leds;
// These sets are arranged in Y-major raster order
const CRGBSet rings[] {
leds(0, 39), leds(40, 79), leds(80, 119), leds(120, 159),
leds(160, 199), leds(200, 239), leds(240, 279), leds(280, 319),
leds(320, 359), leds(360, 399), leds(400, 439), leds(440, 479),
leds(480, 519), leds(520, 559), leds(560, 599), leds(600, 639),
leds(640, 679), leds(680, 719), leds(720, 759), leds(760, 799),
};
void setup() {
// feed the PRNG with some entropy from a floating pin, to get different colours at each boot
pinMode(A0, INPUT);
for (int i = 1024; --i; )
random16_add_entropy(analogRead(A0));
// set a random base colour for each ring
// unless every ring was made from the same batch of LEDs, there will be colour differences
// a small random component to the Hue can help to hide these anomalies.
uint8_t baseHue = random8();
uint8_t baseSat = 63 + random8(64);
for (int i = 0; i < xSize * ySize; i++)
colours[i] = CHSV(baseHue + random8(16), baseSat + random8(128), 150);
// The rings are connected to pins in Y-major raster order
FastLED.addLeds<WS2812B, 14, GRB>(rings[0].leds, rings[0].len);
FastLED.addLeds<WS2812B, 15, GRB>(rings[1].leds, rings[1].len);
FastLED.addLeds<WS2812B, 16, GRB>(rings[2].leds, rings[2].len);
FastLED.addLeds<WS2812B, 17, GRB>(rings[3].leds, rings[3].len);
FastLED.addLeds<WS2812B, 18, GRB>(rings[4].leds, rings[4].len);
FastLED.addLeds<WS2812B, 19, GRB>(rings[5].leds, rings[5].len);
FastLED.addLeds<WS2812B, 20, GRB>(rings[6].leds, rings[6].len);
FastLED.addLeds<WS2812B, 21, GRB>(rings[7].leds, rings[7].len);
FastLED.addLeds<WS2812B, 22, GRB>(rings[8].leds, rings[8].len);
FastLED.addLeds<WS2812B, 23, GRB>(rings[9].leds, rings[9].len);
FastLED.addLeds<WS2812B, 24, GRB>(rings[10].leds, rings[10].len);
FastLED.addLeds<WS2812B, 25, GRB>(rings[11].leds, rings[11].len);
FastLED.addLeds<WS2812B, 26, GRB>(rings[12].leds, rings[12].len);
FastLED.addLeds<WS2812B, 27, GRB>(rings[13].leds, rings[13].len);
FastLED.addLeds<WS2812B, 28, GRB>(rings[14].leds, rings[14].len);
FastLED.addLeds<WS2812B, 29, GRB>(rings[15].leds, rings[15].len);
// These last 4 are ignored, due to FastLED's artificial limit of 16 controllers on Mega2560
FastLED.addLeds<WS2812B, 30, GRB>(rings[16].leds, rings[16].len);
FastLED.addLeds<WS2812B, 31, GRB>(rings[17].leds, rings[17].len);
FastLED.addLeds<WS2812B, 32, GRB>(rings[18].leds, rings[18].len);
FastLED.addLeds<WS2812B, 33, GRB>(rings[19].leds, rings[19].len);
}
void loop() {
static float angle = 30;
angle = fmodf(angle + 0.125f, 360);
windwaves(angle);
FastLED.show();
}
void windwaves(float angle) {
// find the centre of the matrix. For even sizes, add 0.5
const float cx = xSize / 2.f + ((xSize & 1) ? 0 : 0.5f),
cy = ySize / 2.f + ((ySize & 1) ? 0 : 0.5f);
// convert the angle from clockwise degrees to anti-clockwise radians
const float theta = -angle * tau / 360.f;
// to animate the waves, slowly move the phase of the sine towards the origin
const float animTheta = -fmodf(millis() / 128.f, tau);
int count = 0;
for (auto &ring : rings) {
// calculate the X & Y positions of this ring within the matrix
int x = count / ySize; // 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, etc
int y = count % ySize; // 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, etc
// move this ring as if the whole matrix were centred on the origin
float ox = x - cx;
float oy = y - cy;
// rotate this ring around the origin
// https://en.wikipedia.org/wiki/Rotation_matrix
float rx = ox * cosf(theta) - oy * sinf(theta);
float ry = ox * sinf(theta) + oy * cosf(theta);
// now the rotated Y value can be scaled and used as the phase of a sine
// which is then mapped to give a result from 0 to 1
float intensity = sinf(animTheta + ry * 1.75f) * 0.5f + 0.5f;
// retrieve the HSV colour for this ring, and modulate V up to 255
CHSV col = colours[count];
col.value += intensity * (255 - col.value);
// fill all the pixels on this ring with our chosen solid colour
ring.fill_solid(col);
count++;
}
}