#include <FastLED.h>
#define pWIDTH 64
#define pHEIGHT 8
#define NUM_LEDS ((pWIDTH) * (pHEIGHT))
uint8_t *figHue = NULL;
bool loadingFlag = true;
uint8_t rotateParam = 60;
uint8_t need = false;
uint8_t rotateTheta = 0;
uint8_t currentMode = 0;
uint8_t fader = 64;
uint8_t showDelay = 0;
CRGB leds[NUM_LEDS];
void drawPixelXY(int8_t x, int8_t y, CRGB color) {
if (leds == nullptr) return;
if (x < 0 || x > pWIDTH - 1 || y < 0 || y > pHEIGHT - 1) return;
int16_t thisPixel = getPixelNumber(x, y);
if (thisPixel >= 0 && thisPixel < NUM_LEDS) leds[thisPixel] = color;
}
uint16_t getPixelNumber(uint8_t x, uint8_t y) {
if (x >= pWIDTH || y >= pHEIGHT)
return NUM_LEDS;
if (y & 1)
x = pWIDTH - 1 - x;
return x + (y * pWIDTH);
}
void setup() {
FastLED.addLeds<WS2812B, 3, GRB>(leds, NUM_LEDS);
}
void loop() {
static bool figRotateDir = false;
static uint8_t figRotateCount = 1;
static int8_t currentPos = 0;
uint8_t x0 = 4; // pHEIGHT / 2
uint8_t y0 = 4; // pHEIGHT / 2
static uint8_t xSegCount = 1;
static uint8_t ySegCount = 1;
// Переменные для прототипирования
uint8_t xA;
uint8_t xB;
uint8_t xC;
uint8_t xD;
uint8_t yA;
uint8_t yB;
uint8_t yC;
uint8_t yD;
uint8_t xE;
uint8_t xF;
uint8_t xG;
uint8_t xH;
uint8_t yE;
uint8_t yF;
uint8_t yG;
uint8_t yH;
// ================================
uint8_t effectBrightness = 255;
if (loadingFlag) {
xSegCount = pWIDTH/8;
ySegCount = pHEIGHT/8;
if (pWIDTH%8 != 0) xSegCount++;
if (pHEIGHT%8 != 0) ySegCount++;
if (figHue == NULL) {
figHue = new uint8_t [xSegCount*ySegCount];
for (uint8_t i = 0; i < xSegCount * ySegCount; i++) figHue[i] = random8();
}
// modeCode = MC_TEST;
loadingFlag = false;
FastLED.clear(); // очистить
}
// FastLED.clear(); // очистить
fadeToBlackBy(leds, NUM_LEDS, fader);
//blur2d(leds, pWIDTH, pHEIGHT, 20); // не работает
uint8_t figHueNum = 0;
for (uint8_t segNumX = 0; segNumX < xSegCount; segNumX++) {
for (uint8_t segNumY = 0; segNumY < ySegCount; segNumY++) {
uint8_t dotRadiusX = 4;
uint8_t dotRadiusY = 4;
uint8_t x, y;
need = false;
fader = 64;
showDelay = 60;
switch (currentMode) {
case 0: //=== Квадрат ===
drawLineBlend((x0+(segNumX*8) - 4) + currentPos, (y0+(segNumY*8)-1 + 4), (x0+(segNumX*8)-1 + 4), (y0+(segNumY*8)-1 + 4) - currentPos, ColorFromPalette( PartyColors_p, figHue[figHueNum], effectBrightness),192);
drawLineBlend((x0+(segNumX*8)-1 + 4), (y0+(segNumY*8)-1 + 4) - currentPos, (x0+(segNumX*8)-1 + 4) - currentPos, (y0+(segNumY*8) - 4), ColorFromPalette( PartyColors_p, figHue[figHueNum], effectBrightness),192);
drawLineBlend((x0+(segNumX*8)-1 + 4) - currentPos, (y0+(segNumY*8) - 4), (x0+(segNumX*8) - 4), (y0+(segNumY*8) - 4) + currentPos, ColorFromPalette( PartyColors_p, figHue[figHueNum], effectBrightness),192);
drawLineBlend((x0+(segNumX*8) - 4), (y0+(segNumY*8) - 4) + currentPos, (x0+(segNumX*8) - 4) + currentPos, (y0+(segNumY*8)-1 + 4), ColorFromPalette( PartyColors_p, figHue[figHueNum], effectBrightness),192);
break;
case 1: //=== Пропеллер ===
drawLineBlend((x0+(segNumX*8) - 4) + currentPos, (y0+(segNumY*8)-1 + 4), x0+(segNumX*8)-1, y0+(segNumY*8), ColorFromPalette( PartyColors_p, figHue[figHueNum]+128, effectBrightness),192);
drawLineBlend((x0+(segNumX*8)-1 + 4), (y0+(segNumY*8)-1 + 4) - currentPos, x0+(segNumX*8), y0+(segNumY*8), ColorFromPalette( PartyColors_p, figHue[figHueNum]+128, effectBrightness),192);
drawLineBlend((x0+(segNumX*8)-1 + 4) - currentPos, (y0+(segNumY*8) - 4), x0+(segNumX*8), y0+(segNumY*8)-1, ColorFromPalette( PartyColors_p, figHue[figHueNum]+128, effectBrightness),192);
drawLineBlend((x0+(segNumX*8) - 4), (y0+(segNumY*8) - 4) + currentPos, x0+(segNumX*8)-1, y0+(segNumY*8)-1, ColorFromPalette( PartyColors_p, figHue[figHueNum]+128, effectBrightness),192);
break;
case 2: //=== Вращающиеся круги ===
drawCircle((x0+(segNumX*8)), (y0+(segNumY*8)), 1, ColorFromPalette( PartyColors_p, figHue[figHueNum], effectBrightness), (uint8_t)(3-currentPos/2));
drawCircle((x0+(segNumX*8)), (y0+(segNumY*8)), 3, ColorFromPalette( PartyColors_p, figHue[figHueNum], effectBrightness), (uint8_t)(currentPos/2));
break;
case 3: //=== Размерные круги ===
drawCircle((x0+(segNumX*8)), (y0+(segNumY*8)), (uint8_t)currentPos/2, ColorFromPalette( PartyColors_p, figHue[figHueNum], effectBrightness));
break;
case 4: //=== Вращающиеся круги (filled) ===
drawCircle((x0+(segNumX*8)), (y0+(segNumY*8)), 3, ColorFromPalette( PartyColors_p, figHue[figHueNum], effectBrightness),3-(uint8_t)currentPos/2,true);
break;
case 5: //===
dotRadiusX = 3;
dotRadiusY = 3;
need = true;
x = ((x0+(segNumX*8))-dotRadiusX) + scale8(sin8(256/8*currentPos), ((x0+(segNumX*8))+dotRadiusX) - ((x0+(segNumX*8))-dotRadiusX));
y = ((y0+(segNumY*8))-dotRadiusY) + scale8(cos8(256/8*currentPos), ((y0+(segNumY*8))+dotRadiusY) - ((y0+(segNumY*8))-dotRadiusY));
drawLineBlend((x0+(segNumX*8)), (y0+(segNumY*8)), x, y, ColorFromPalette( PartyColors_p, figHue[figHueNum], effectBrightness), 255);
break;
case 6: //=== test ===
dotRadiusX = 4;
dotRadiusY = 4;
need = true;
fader = 8;
showDelay = 20;
//===
//uint8_t x = (x0-dotRadius) + scale8(sin8(256/8*currentPos), (x0+dotRadius) - (x0-dotRadius));
//uint8_t y = (y0-dotRadius) + scale8(cos8(256/8*currentPos), (y0+dotRadius) - (y0-dotRadius));
x = (x0-dotRadiusX) + scale8(sin8(rotateTheta), (x0+dotRadiusX-1) - (x0-dotRadiusX));
y = (y0-dotRadiusY) + scale8(cos8(rotateTheta), (y0+dotRadiusY-1) - (y0-dotRadiusY));
uint16_t pixNum = getPixelNumber(x+(segNumX*8), y+(segNumY*8));
if (pixNum >=0 && pixNum < NUM_LEDS) leds[pixNum] = ColorFromPalette( PartyColors_p, figHue[figHueNum], effectBrightness);
dotRadiusX = 2;
dotRadiusY = 2;
x = (x0-dotRadiusX) + scale8(sin8(127-rotateTheta), (x0+dotRadiusX-1) - (x0-dotRadiusX));
y = (y0-dotRadiusY) + scale8(cos8(127-rotateTheta), (y0+dotRadiusY-1) - (y0-dotRadiusY));
pixNum = getPixelNumber(x+(segNumX*8), y+(segNumY*8));
if (pixNum >=0 && pixNum < NUM_LEDS) leds[pixNum] = ColorFromPalette( PartyColors_p, figHue[figHueNum], effectBrightness);
break;
}
figHueNum++;
}
}
rotateTheta+=8;
if (!figRotateDir) {if (currentPos++ >= 8-((need)?0:1)) {currentPos = ((need)?0:1); figRotateCount++;}}
else if (figRotateDir) {if (currentPos-- <= ((need)?0:1)) {currentPos = 8-((need)?0:1); figRotateCount++;}}
//if (!figRotateDir) {if (currentPos++ >= (4-((need)?0:1))*2) {currentPos = 0; figRotateCount++;}}
//else if (figRotateDir) {if (currentPos-- <= ((need)?0:1)) {currentPos = 8-((need)?0:1); figRotateCount++;}}
if (rotateParam < 5) figRotateDir = true;
else if (rotateParam > 250) figRotateDir = false;
else {
if (figRotateCount >= map8(rotateParam,1,8)) {
figRotateDir = !figRotateDir;
if (!figRotateDir) currentPos = ((need)?0:1);
if (figRotateDir) currentPos = 8-((need)?0:1);
figRotateCount = 0;
for (uint8_t i = 0; i < xSegCount * ySegCount; i++) figHue[i] = random8();
}
}
FastLED.delay(showDelay);
}
void drawLineBlend(int x1, int y1, int x2, int y2, CRGB color, uint8_t amount) {
int deltaX = abs(x2 - x1);
int deltaY = abs(y2 - y1);
int signX = x1 < x2 ? 1 : -1;
int signY = y1 < y2 ? 1 : -1;
int error = deltaX - deltaY;
int16_t pn;
pn = getPixelNumber(x2, y2); if (pn >= 0 && pn < NUM_LEDS) nblend(leds[pn], color, amount);
while (x1 != x2 || y1 != y2) {
pn = getPixelNumber(x1, y1); if (pn >= 0 && pn < NUM_LEDS) nblend(leds[pn], color, amount);
int error2 = error * 2;
if (error2 > -deltaY) {
error -= deltaY;
x1 += signX;
}
if (error2 < deltaX) {
error += deltaX;
y1 += signY;
}
}
}
void drawCircle(int x0, int y0, int radius, CRGB color){
int a = radius, b = 0;
int radiusError = 1 - a;
int xOffset = (pWIDTH%2==0)?1:0;
int yOffset = (pHEIGHT%2==0)?1:0;
if (radius == 0) {
if (pWIDTH%2!=0 && pHEIGHT%2!=0) drawPixelXY(x0, y0, color);
else {
//if (pWIDTH%2==0){
drawPixelXY(x0-xOffset, y0-yOffset, color);
drawPixelXY(x0, y0-yOffset, color);
//}
//if (pHEIGHT%2==0){
drawPixelXY(x0, y0, color);
drawPixelXY(x0-xOffset, y0, color);
//}
}
return;
}
while (a >= b) {
drawPixelXY(a + x0, -b + y0-yOffset, color); //ru
drawPixelXY(b + x0, -a + y0-yOffset, color); //ru
drawPixelXY(a + x0, b + y0, color); //rb
drawPixelXY(b + x0, a + y0, color); //rb
drawPixelXY(-a + x0-xOffset, b + y0, color); //lb
drawPixelXY(-b + x0-xOffset, a + y0, color); //lb
drawPixelXY(-a + x0-xOffset, -b + y0-yOffset, color); //lu
drawPixelXY(-b + x0-xOffset, -a + y0-yOffset, color); //lu
b++;
if (radiusError < 0) {
radiusError += 2 * b + 1;
} else {
a--;
radiusError += 2 * (b - a + 1);
}
}
}
void drawCircle(int x0, int y0, int radius, CRGB color, int quadrant){
int a = radius, b = 0;
int radiusError = 1 - a;
int xOffset = (pWIDTH%2==0)?1:0;
int yOffset = (pHEIGHT%2==0)?1:0;
if (radius == 0) {
if (pWIDTH%2!=0 && pHEIGHT%2!=0) drawPixelXY(x0, y0, color);
else {
//if (pWIDTH%2==0){
drawPixelXY(x0-xOffset, y0-yOffset, color);
drawPixelXY(x0, y0-yOffset, color);
//}
//if (pHEIGHT%2==0){
drawPixelXY(x0, y0, color);
drawPixelXY(x0-xOffset, y0, color);
//}
}
return;
}
while (a >= b) {
switch (quadrant) {
case 0: drawPixelXY(a + x0, -b + y0-yOffset, color); //ru
drawPixelXY(b + x0, -a + y0-yOffset, color); //ru
break;
case 1: drawPixelXY(a + x0, b + y0, color); //rb
drawPixelXY(b + x0, a + y0, color); //rb
break;
case 2: drawPixelXY(-a + x0-xOffset, b + y0, color); //lb
drawPixelXY(-b + x0-xOffset, a + y0, color); //lb
break;
case 3: drawPixelXY(-a + x0-xOffset, -b + y0-yOffset, color); //lu
drawPixelXY(-b + x0-xOffset, -a + y0-yOffset, color); //lu
break;
}
b++;
if (radiusError < 0) {
radiusError += 2 * b + 1;
} else {
a--;
radiusError += 2 * (b - a + 1);
}
}
}
void drawCircle(int x0, int y0, int radius, CRGB color, int quadrant, bool fill){
int a = radius, b = 0;
int radiusError = 1 - a;
int xOffset = (pWIDTH%2==0)?1:0;
int yOffset = (pHEIGHT%2==0)?1:0;
if (radius == 0) {
if (pWIDTH%2!=0 && pHEIGHT%2!=0) drawPixelXY(x0, y0, color);
else {
//if (pWIDTH%2==0){
drawPixelXY(x0-xOffset, y0-yOffset, color);
drawPixelXY(x0, y0-yOffset, color);
//}
//if (pHEIGHT%2==0){
drawPixelXY(x0, y0, color);
drawPixelXY(x0-xOffset, y0, color);
//}
}
return;
}
while (a >= b) {
switch (quadrant) {
case 0: if (!fill) {
drawPixelXY(a + x0, -b + y0-yOffset, color); //ru
drawPixelXY(b + x0, -a + y0-yOffset, color); //ru
} else {
drawLineBlend(x0, y0-yOffset, a + x0, -b + y0-yOffset, color, 255); //ru
drawLineBlend(x0, y0-yOffset, b + x0, -a + y0-yOffset, color, 255); //ru
}
break;
case 1: if (!fill) {
drawPixelXY(a + x0, b + y0, color); //rb
drawPixelXY(b + x0, a + y0, color); //rb
} else {
drawLineBlend(x0, y0, a + x0, b + y0, color, 255); //rb
drawLineBlend(x0, y0, b + x0, a + y0, color, 255); //rb
}
break;
case 2: if (!fill) {
drawPixelXY(-a + x0-xOffset, b + y0, color); //lb
drawPixelXY(-b + x0-xOffset, a + y0, color); //lb
} else {
drawLineBlend(x0-xOffset, y0, -a + x0-xOffset, b + y0, color, 255); //lb
drawLineBlend(x0-xOffset, y0, -b + x0-xOffset, a + y0, color, 255); //lb
}
break;
case 3: if (!fill) {
drawPixelXY(-a + x0-xOffset, -b + y0-yOffset, color); //lu
drawPixelXY(-b + x0-xOffset, -a + y0-yOffset, color); //lu
} else {
drawLineBlend(x0-xOffset, y0-yOffset, -a + x0-xOffset, -b + y0-yOffset, color, 255); //lu
drawLineBlend(x0-xOffset, y0-yOffset, -b + x0-xOffset, -a + y0-yOffset, color, 255); //lu
}
break;
}
b++;
if (radiusError < 0) {
radiusError += 2 * b + 1;
} else {
a--;
radiusError += 2 * (b - a + 1);
}
}
}