#include <FastLED.h>
#define LED_PIN 3
#define COLOR_ORDER GRB
#define CHIPSET WS2812B
#define kMatrixWidth 16
#define kMatrixHeight 16
#define kMatrixSerpentine true
#define kMatrixRowMajor true
#define kMatrixFlipMajor true
#define kMatrixFlipMinor false
#define NUM_LEDS ((kMatrixWidth) * (kMatrixHeight))
CRGB leds_plus_safety_pixel[ NUM_LEDS + 1];
CRGB* const leds( leds_plus_safety_pixel + 1);
void setup() {
Serial.begin(115200);
FastLED.addLeds<CHIPSET, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection(UncorrectedColor);
}
void loop() {
drawFrame();
FastLED.show();
FastLED.clear();
}
int16_t XY(int8_t x, int8_t y) {
uint8_t major, minor, sz_major, sz_minor;
if (x >= kMatrixWidth || y >= kMatrixHeight || x < 0 || y < 0) return -1;
if (kMatrixRowMajor)
major = x, minor = y, sz_major = kMatrixWidth, sz_minor = kMatrixHeight;
else
major = y, minor = x, sz_major = kMatrixHeight, sz_minor = kMatrixWidth;
if (kMatrixFlipMajor ^ (minor & 1 && kMatrixSerpentine))
major = sz_major - 1 - major;
if (kMatrixFlipMinor)
minor = sz_minor - 1 - minor;
return (uint16_t) minor * sz_major + major;
}
void drawFrame() {
float ms = millis() / 500.f;
const float kHalfWidth = kMatrixWidth / 2;
const float kHalfHeight = kMatrixHeight / 2;
const float density = 1.0875f + 0.0675f * sinf(ms * 0.29f);
for (float y = 0; y <= kHalfHeight + 2; y += density)
for (float x = 0; x <= kHalfWidth + 2; x += density) {
float hyp = hypotf(x, y) * -3.f;
float fx = sinf(ms + hyp / 8.f) * 224.f;
float fy = cosf(ms * .78f + hyp / 8.f) * 224.f;
CRGB col = ColorFromPaletteExtended(RainbowColors_p, (ms * 24.f + hyp * 4.f) * 256.f, 255, LINEARBLEND);
wu_pixel(256 * (x + kHalfWidth) + fx, 256 * (y + kHalfHeight) + fy, &col);
if (x) wu_pixel(256 * (-x + kHalfWidth) + fx, 256 * (y + kHalfHeight) + fy, &col);
if (y) wu_pixel(256 * (x + kHalfWidth) + fx, 256 * (-y + kHalfHeight) + fy, &col);
if (x && y) wu_pixel(256 * (-x + kHalfWidth) + fx, 256 * (-y + kHalfHeight) + fy, &col);
}
// fade out/in a box in the middle of the matrix
static int fadeLevel = 0;
static int fadeStep = 5;
for (byte y = 5; y < 12; y++) {
for (byte x = 5; x < 12; x++) {
leds[XY(x, y)].fadeToBlackBy(fadeLevel);
}
}
fadeLevel += fadeStep;
if (fadeLevel >= 255) {
fadeLevel = 255;
fadeStep = -fadeStep;
}
if (fadeLevel <= 0) {
fadeLevel = 0;
fadeStep = -fadeStep;
}
}
void wu_pixel(int16_t x, int16_t y, CRGB* col) {
// 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++) {
int16_t local_x = (x >> 8) + (i & 1);
int16_t local_y = (y >> 8) + ((i >> 1) & 1);
int16_t xy = XY(local_x, local_y);
if (xy < 0) continue;
leds[xy].r = qadd8(leds[xy].r, col->r * wu[i] >> 8);
leds[xy].g = qadd8(leds[xy].g, col->g * wu[i] >> 8);
leds[xy].b = qadd8(leds[xy].b, col->b * wu[i] >> 8);
}
}
// from: https://github.com/FastLED/FastLED/pull/202
CRGB ColorFromPaletteExtended(const CRGBPalette16& pal, uint16_t index, uint8_t brightness, TBlendType blendType) {
// Extract the four most significant bits of the index as a palette index.
uint8_t index_4bit = (index >> 12);
// Calculate the 8-bit offset from the palette index.
uint8_t offset = (uint8_t)(index >> 4);
// Get the palette entry from the 4-bit index
const CRGB* entry = &(pal[0]) + index_4bit;
uint8_t red1 = entry->red;
uint8_t green1 = entry->green;
uint8_t blue1 = entry->blue;
uint8_t blend = offset && (blendType != NOBLEND);
if (blend) {
if (index_4bit == 15) {
entry = &(pal[0]);
} else {
entry++;
}
// Calculate the scaling factor and scaled values for the lower palette value.
uint8_t f1 = 255 - offset;
red1 = scale8_LEAVING_R1_DIRTY(red1, f1);
green1 = scale8_LEAVING_R1_DIRTY(green1, f1);
blue1 = scale8_LEAVING_R1_DIRTY(blue1, f1);
// Calculate the scaled values for the neighbouring palette value.
uint8_t red2 = entry->red;
uint8_t green2 = entry->green;
uint8_t blue2 = entry->blue;
red2 = scale8_LEAVING_R1_DIRTY(red2, offset);
green2 = scale8_LEAVING_R1_DIRTY(green2, offset);
blue2 = scale8_LEAVING_R1_DIRTY(blue2, offset);
cleanup_R1();
// These sums can't overflow, so no qadd8 needed.
red1 += red2;
green1 += green2;
blue1 += blue2;
}
if (brightness != 255) {
// nscale8x3_video(red1, green1, blue1, brightness);
nscale8x3(red1, green1, blue1, brightness);
}
return CRGB(red1, green1, blue1);
}