mirror of
https://github.com/gunner47/GyverLamp.git
synced 2025-08-06 16:47:17 +03:00
733 lines
24 KiB
C++
733 lines
24 KiB
C++
// ============= ЭФФЕКТЫ ===============
|
||
|
||
// ------------- конфетти --------------
|
||
#define FADE_OUT_SPEED (70U) // скорость затухания
|
||
void sparklesRoutine()
|
||
{
|
||
for (uint8_t i = 0; i < modes[EFF_SPARKLES].Scale; i++)
|
||
{
|
||
uint8_t x = random(0U, WIDTH);
|
||
uint8_t y = random(0U, HEIGHT);
|
||
if (getPixColorXY(x, y) == 0U)
|
||
{
|
||
leds[getPixelNumber(x, y)] = CHSV(random(0U, 255U), 255U, 255U);
|
||
}
|
||
}
|
||
fader(FADE_OUT_SPEED);
|
||
}
|
||
|
||
// функция плавного угасания цвета для всех пикселей
|
||
void fader(uint8_t step)
|
||
{
|
||
for (uint8_t i = 0U; i < WIDTH; i++)
|
||
{
|
||
for (uint8_t j = 0U; j < HEIGHT; j++)
|
||
{
|
||
fadePixel(i, j, step);
|
||
}
|
||
}
|
||
}
|
||
|
||
void fadePixel(uint8_t i, uint8_t j, uint8_t step) // новый фейдер
|
||
{
|
||
int32_t pixelNum = getPixelNumber(i, j);
|
||
if (getPixColor(pixelNum) == 0U) return;
|
||
|
||
if (leds[pixelNum].r >= 30U ||
|
||
leds[pixelNum].g >= 30U ||
|
||
leds[pixelNum].b >= 30U)
|
||
{
|
||
leds[pixelNum].fadeToBlackBy(step);
|
||
}
|
||
else
|
||
{
|
||
leds[pixelNum] = 0U;
|
||
}
|
||
}
|
||
|
||
// ------------- огонь -----------------
|
||
#define SPARKLES (1U) // вылетающие угольки вкл выкл
|
||
uint8_t line[WIDTH];
|
||
uint8_t pcnt = 0U;
|
||
|
||
//these values are substracetd from the generated values to give a shape to the animation
|
||
static const uint8_t valueMask[8][16] PROGMEM =
|
||
{
|
||
{32 , 0 , 0 , 0 , 0 , 0 , 0 , 32 , 32 , 0 , 0 , 0 , 0 , 0 , 0 , 32 },
|
||
{64 , 0 , 0 , 0 , 0 , 0 , 0 , 64 , 64 , 0 , 0 , 0 , 0 , 0 , 0 , 64 },
|
||
{96 , 32 , 0 , 0 , 0 , 0 , 32 , 96 , 96 , 32 , 0 , 0 , 0 , 0 , 32 , 96 },
|
||
{128, 64 , 32 , 0 , 0 , 32 , 64 , 128, 128, 64 , 32 , 0 , 0 , 32 , 64 , 128},
|
||
{160, 96 , 64 , 32 , 32 , 64 , 96 , 160, 160, 96 , 64 , 32 , 32 , 64 , 96 , 160},
|
||
{192, 128, 96 , 64 , 64 , 96 , 128, 192, 192, 128, 96 , 64 , 64 , 96 , 128, 192},
|
||
{255, 160, 128, 96 , 96 , 128, 160, 255, 255, 160, 128, 96 , 96 , 128, 160, 255},
|
||
{255, 192, 160, 128, 128, 160, 192, 255, 255, 192, 160, 128, 128, 160, 192, 255}
|
||
};
|
||
|
||
//these are the hues for the fire,
|
||
//should be between 0 (red) to about 25 (yellow)
|
||
static const uint8_t hueMask[8][16] PROGMEM =
|
||
{
|
||
{1 , 11, 19, 25, 25, 22, 11, 1 , 1 , 11, 19, 25, 25, 22, 11, 1 },
|
||
{1 , 8 , 13, 19, 25, 19, 8 , 1 , 1 , 8 , 13, 19, 25, 19, 8 , 1 },
|
||
{1 , 8 , 13, 16, 19, 16, 8 , 1 , 1 , 8 , 13, 16, 19, 16, 8 , 1 },
|
||
{1 , 5 , 11, 13, 13, 13, 5 , 1 , 1 , 5 , 11, 13, 13, 13, 5 , 1 },
|
||
{1 , 5 , 11, 11, 11, 11, 5 , 1 , 1 , 5 , 11, 11, 11, 11, 5 , 1 },
|
||
{0 , 1 , 5 , 8 , 8 , 5 , 1 , 0 , 0 , 1 , 5 , 8 , 8 , 5 , 1 , 0 },
|
||
{0 , 0 , 1 , 5 , 5 , 1 , 0 , 0 , 0 , 0 , 1 , 5 , 5 , 1 , 0 , 0 },
|
||
{0 , 0 , 0 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 1 , 0 , 0 , 0 }
|
||
};
|
||
|
||
void fireRoutine(bool isColored) // true - цветной огонь, false - белый
|
||
{
|
||
if (loadingFlag)
|
||
{
|
||
loadingFlag = false;
|
||
FastLED.clear();
|
||
generateLine();
|
||
memset(matrixValue, 0, sizeof(matrixValue));
|
||
}
|
||
if (pcnt >= 100)
|
||
{
|
||
shiftUp();
|
||
generateLine();
|
||
pcnt = 0;
|
||
}
|
||
drawFrame(pcnt, isColored);
|
||
pcnt += 30;
|
||
}
|
||
|
||
// Randomly generate the next line (matrix row)
|
||
void generateLine()
|
||
{
|
||
for (uint8_t x = 0U; x < WIDTH; x++)
|
||
{
|
||
line[x] = random(64, 255);
|
||
}
|
||
}
|
||
|
||
void shiftUp()
|
||
{
|
||
for (uint8_t y = HEIGHT - 1U; y > 0U; y--)
|
||
{
|
||
for (uint8_t x = 0U; x < WIDTH; x++)
|
||
{
|
||
uint8_t newX = x;
|
||
if (x > 15U) newX = x % 16U;
|
||
if (y > 7U) continue;
|
||
matrixValue[y][newX] = matrixValue[y - 1U][newX];
|
||
}
|
||
}
|
||
|
||
for (uint8_t x = 0U; x < WIDTH; x++)
|
||
{
|
||
uint8_t newX = x;
|
||
if (x > 15U) newX = x % 16U;
|
||
matrixValue[0U][newX] = line[newX];
|
||
}
|
||
}
|
||
|
||
// draw a frame, interpolating between 2 "key frames"
|
||
// @param pcnt percentage of interpolation
|
||
|
||
void drawFrame(uint8_t pcnt, bool isColored)
|
||
{
|
||
int32_t nextv;
|
||
|
||
//each row interpolates with the one before it
|
||
for (uint8_t y = HEIGHT - 1U; y > 0U; y--)
|
||
{
|
||
for (uint8_t x = 0U; x < WIDTH; x++)
|
||
{
|
||
uint8_t newX = x;
|
||
if (x > 15U) newX = x % 16U;
|
||
if (y < 8U)
|
||
{
|
||
nextv =
|
||
(((100.0 - pcnt) * matrixValue[y][newX]
|
||
+ pcnt * matrixValue[y - 1][newX]) / 100.0)
|
||
- pgm_read_byte(&valueMask[y][newX]);
|
||
|
||
CRGB color = CHSV(
|
||
isColored ? modes[EFF_FIRE].Scale * 2.5 + pgm_read_byte(&hueMask[y][newX]) : 0U, // H
|
||
isColored ? 255U : 0U, // S
|
||
(uint8_t)max(0, nextv) // V
|
||
);
|
||
|
||
leds[getPixelNumber(x, y)] = color;
|
||
}
|
||
else if (y == 8U && SPARKLES)
|
||
{
|
||
if (random(0, 20) == 0 && getPixColorXY(x, y - 1U) != 0U) drawPixelXY(x, y, getPixColorXY(x, y - 1U));
|
||
else drawPixelXY(x, y, 0U);
|
||
}
|
||
else if (SPARKLES)
|
||
{
|
||
// старая версия для яркости
|
||
if (getPixColorXY(x, y - 1U) > 0U)
|
||
drawPixelXY(x, y, getPixColorXY(x, y - 1U));
|
||
else drawPixelXY(x, y, 0U);
|
||
}
|
||
}
|
||
}
|
||
|
||
//first row interpolates with the "next" line
|
||
for (uint8_t x = 0U; x < WIDTH; x++)
|
||
{
|
||
uint8_t newX = x;
|
||
if (x > 15U) newX = x % 16U;
|
||
CRGB color = CHSV(
|
||
isColored ? modes[EFF_FIRE].Scale * 2.5 + pgm_read_byte(&(hueMask[0][newX])): 0U, // H
|
||
isColored ? 255U : 0U, // S
|
||
(uint8_t)(((100.0 - pcnt) * matrixValue[0][newX] + pcnt * line[newX]) / 100.0) // V
|
||
);
|
||
//leds[getPixelNumber(newX, 0)] = color; // на форуме пишут что это ошибка - вместо newX должно быть x, иначе
|
||
leds[getPixelNumber(x, 0)] = color; // на матрицах шире 16 столбцов нижний правый угол неработает
|
||
}
|
||
}
|
||
|
||
// ------------- радуга вертикальная ----------------
|
||
uint8_t hue;
|
||
void rainbowVerticalRoutine()
|
||
{
|
||
hue += 4;
|
||
for (uint8_t j = 0; j < HEIGHT; j++)
|
||
{
|
||
CHSV thisColor = CHSV((uint8_t)(hue + j * modes[EFF_RAINBOW_VER].Scale), 255, 255);
|
||
for (uint8_t i = 0U; i < WIDTH; i++)
|
||
{
|
||
drawPixelXY(i, j, thisColor);
|
||
}
|
||
}
|
||
}
|
||
|
||
// ------------- радуга горизонтальная ----------------
|
||
void rainbowHorizontalRoutine()
|
||
{
|
||
hue += 4;
|
||
for (uint8_t i = 0U; i < WIDTH; i++)
|
||
{
|
||
CHSV thisColor = CHSV((uint8_t)(hue + i * modes[EFF_RAINBOW_HOR].Scale), 255, 255);
|
||
for (uint8_t j = 0U; j < HEIGHT; j++)
|
||
{
|
||
drawPixelXY(i, j, thisColor);
|
||
}
|
||
}
|
||
}
|
||
|
||
// ------------- радуга диагональная -------------
|
||
void rainbowDiagonalRoutine()
|
||
{
|
||
if (loadingFlag)
|
||
{
|
||
loadingFlag = false;
|
||
FastLED.clear();
|
||
}
|
||
|
||
hue += 8;
|
||
for (uint8_t i = 0U; i < WIDTH; i++)
|
||
{
|
||
for (uint8_t j = 0U; j < HEIGHT; j++)
|
||
{
|
||
float twirlFactor = 3.0F * (modes[EFF_RAINBOW_DIAG].Scale / 100.0F); // на сколько оборотов будет закручена матрица, [0..3]
|
||
CRGB thisColor = CHSV((uint8_t)(hue + (float)(WIDTH / HEIGHT * i + j * twirlFactor) * (float)(255 / maxDim)), 255, 255);
|
||
drawPixelXY(i, j, thisColor);
|
||
}
|
||
}
|
||
}
|
||
|
||
// ------------- цвета -----------------
|
||
void colorsRoutine()
|
||
{
|
||
if (loadingFlag)
|
||
{
|
||
hue += modes[EFF_COLORS].Scale;
|
||
|
||
for (uint16_t i = 0U; i < NUM_LEDS; i++)
|
||
{
|
||
leds[i] = CHSV(hue, 255U, 255U);
|
||
}
|
||
}
|
||
}
|
||
|
||
// ------------- цвет ------------------
|
||
void colorRoutine()
|
||
{
|
||
if (loadingFlag)
|
||
{
|
||
loadingFlag = false;
|
||
FastLED.clear();
|
||
|
||
for (int16_t i = 0U; i < NUM_LEDS; i++)
|
||
{
|
||
leds[i] = CHSV(modes[EFF_COLOR].Scale * 2.5, 255U, 255U);
|
||
}
|
||
}
|
||
}
|
||
|
||
// ------------- снегопад ----------
|
||
void snowRoutine()
|
||
{
|
||
// сдвигаем всё вниз
|
||
for (uint8_t x = 0U; x < WIDTH; x++)
|
||
{
|
||
for (uint8_t y = 0U; y < HEIGHT - 1; y++)
|
||
{
|
||
drawPixelXY(x, y, getPixColorXY(x, y + 1U));
|
||
}
|
||
}
|
||
|
||
for (uint8_t x = 0U; x < WIDTH; x++)
|
||
{
|
||
// заполняем случайно верхнюю строку
|
||
// а также не даём двум блокам по вертикали вместе быть
|
||
if (getPixColorXY(x, HEIGHT - 2U) == 0U && (random(0, 100 - modes[EFF_SNOW].Scale) == 0U))
|
||
drawPixelXY(x, HEIGHT - 1U, 0xE0FFFF - 0x101010 * random(0, 4));
|
||
else
|
||
drawPixelXY(x, HEIGHT - 1U, 0x000000);
|
||
}
|
||
}
|
||
|
||
// ------------- метель -------------
|
||
#define SNOW_DENSE (60U) // плотность снега
|
||
#define SNOW_TAIL_STEP (100U) // длина хвоста
|
||
#define SNOW_SATURATION (0U) // насыщенность (от 0 до 255)
|
||
void snowStormRoutine()
|
||
{
|
||
if (loadingFlag)
|
||
{
|
||
loadingFlag = false;
|
||
FastLED.clear();
|
||
}
|
||
|
||
// заполняем головами комет левую и верхнюю линию
|
||
for (uint8_t i = HEIGHT / 2U; i < HEIGHT; i++)
|
||
{
|
||
if (getPixColorXY(0U, i) == 0U &&
|
||
(random(0, SNOW_DENSE) == 0) &&
|
||
getPixColorXY(0U, i + 1U) == 0U &&
|
||
getPixColorXY(0U, i - 1U) == 0U)
|
||
{
|
||
leds[getPixelNumber(0U, i)] = CHSV(random(0, 200), SNOW_SATURATION, 255U);
|
||
}
|
||
}
|
||
|
||
for (uint8_t i = 0U; i < WIDTH / 2U; i++)
|
||
{
|
||
if (getPixColorXY(i, HEIGHT - 1U) == 0U &&
|
||
(random(0, map(modes[EFF_SNOWSTORM].Scale, 0U, 255U, 10U, 120U)) == 0U) &&
|
||
getPixColorXY(i + 1U, HEIGHT - 1U) == 0U &&
|
||
getPixColorXY(i - 1U, HEIGHT - 1U) == 0U)
|
||
{
|
||
leds[getPixelNumber(i, HEIGHT - 1U)] = CHSV(random(0, 200), SNOW_SATURATION, 255U);
|
||
}
|
||
}
|
||
|
||
// сдвигаем по диагонали
|
||
for (uint8_t y = 0U; y < HEIGHT - 1U; y++)
|
||
{
|
||
for (uint8_t x = WIDTH - 1U; x > 0U; x--)
|
||
{
|
||
drawPixelXY(x, y, getPixColorXY(x - 1U, y + 1U));
|
||
}
|
||
}
|
||
|
||
// уменьшаем яркость левой и верхней линии, формируем "хвосты"
|
||
for (uint8_t i = HEIGHT / 2U; i < HEIGHT; i++)
|
||
{
|
||
fadePixel(0U, i, SNOW_TAIL_STEP);
|
||
}
|
||
for (uint8_t i = 0U; i < WIDTH / 2U; i++)
|
||
{
|
||
fadePixel(i, HEIGHT - 1U, SNOW_TAIL_STEP);
|
||
}
|
||
}
|
||
|
||
// ------------- звездопад -------------
|
||
#define STAR_DENSE (60U) // плотность комет
|
||
#define STAR_TAIL_STEP (100U) // длина хвоста кометы
|
||
#define STAR_SATURATION (150U) // насыщенность кометы (от 0 до 255)
|
||
void starfallRoutine()
|
||
{
|
||
if (loadingFlag)
|
||
{
|
||
loadingFlag = false;
|
||
FastLED.clear();
|
||
}
|
||
|
||
// заполняем головами комет левую и верхнюю линию
|
||
for (uint8_t i = HEIGHT / 2U; i < HEIGHT; i++)
|
||
{
|
||
if (getPixColorXY(0U, i) == 0U &&
|
||
(random(0, STAR_DENSE) == 0) &&
|
||
getPixColorXY(0U, i + 1U) == 0U &&
|
||
getPixColorXY(0U, i - 1U) == 0U)
|
||
{
|
||
leds[getPixelNumber(0U, i)] = CHSV(random(0, 200), STAR_SATURATION, 255U);
|
||
}
|
||
}
|
||
|
||
for (uint8_t i = 0U; i < WIDTH / 2U; i++)
|
||
{
|
||
if (getPixColorXY(i, HEIGHT - 1U) == 0U &&
|
||
(random(0, map(modes[EFF_STARFALL].Scale, 0U, 255U, 10U, 120U)) == 0U) &&
|
||
getPixColorXY(i + 1U, HEIGHT - 1U) == 0U &&
|
||
getPixColorXY(i - 1U, HEIGHT - 1U) == 0U)
|
||
{
|
||
leds[getPixelNumber(i, HEIGHT - 1U)] = CHSV(random(0, 200), STAR_SATURATION, 255U);
|
||
}
|
||
}
|
||
|
||
// сдвигаем по диагонали
|
||
for (uint8_t y = 0U; y < HEIGHT - 1U; y++)
|
||
{
|
||
for (uint8_t x = WIDTH - 1U; x > 0U; x--)
|
||
{
|
||
drawPixelXY(x, y, getPixColorXY(x - 1U, y + 1U));
|
||
}
|
||
}
|
||
|
||
// уменьшаем яркость левой и верхней линии, формируем "хвосты"
|
||
for (uint8_t i = HEIGHT / 2U; i < HEIGHT; i++)
|
||
{
|
||
fadePixel(0U, i, STAR_TAIL_STEP);
|
||
}
|
||
for (uint8_t i = 0U; i < WIDTH / 2U; i++)
|
||
{
|
||
fadePixel(i, HEIGHT - 1U, STAR_TAIL_STEP);
|
||
}
|
||
}
|
||
|
||
// ------------- матрица ---------------
|
||
void matrixRoutine()
|
||
{
|
||
for (uint8_t x = 0U; x < WIDTH; x++)
|
||
{
|
||
// заполняем случайно верхнюю строку
|
||
uint32_t thisColor = getPixColorXY(x, HEIGHT - 1U);
|
||
if (thisColor == 0U)
|
||
drawPixelXY(x, HEIGHT - 1U, 0x00FF00 * (random(0, 100 - modes[EFF_MATRIX].Scale) == 0U));
|
||
else if (thisColor < 0x002000)
|
||
drawPixelXY(x, HEIGHT - 1U, 0U);
|
||
else
|
||
drawPixelXY(x, HEIGHT - 1U, thisColor - 0x002000);
|
||
}
|
||
|
||
// сдвигаем всё вниз
|
||
for (uint8_t x = 0U; x < WIDTH; x++)
|
||
{
|
||
for (uint8_t y = 0U; y < HEIGHT - 1U; y++)
|
||
{
|
||
drawPixelXY(x, y, getPixColorXY(x, y + 1U));
|
||
}
|
||
}
|
||
}
|
||
|
||
// ------------- светлячки --------------
|
||
#define LIGHTERS_AM (100U)
|
||
int32_t lightersPos[2U][LIGHTERS_AM];
|
||
int8_t lightersSpeed[2U][LIGHTERS_AM];
|
||
CHSV lightersColor[LIGHTERS_AM];
|
||
uint8_t loopCounter;
|
||
int32_t angle[LIGHTERS_AM];
|
||
int32_t speedV[LIGHTERS_AM];
|
||
int8_t angleSpeed[LIGHTERS_AM];
|
||
void lightersRoutine()
|
||
{
|
||
if (loadingFlag)
|
||
{
|
||
loadingFlag = false;
|
||
randomSeed(millis());
|
||
for (uint8_t i = 0U; i < LIGHTERS_AM; i++)
|
||
{
|
||
lightersPos[0U][i] = random(0, WIDTH * 10);
|
||
lightersPos[1U][i] = random(0, HEIGHT * 10);
|
||
lightersSpeed[0U][i] = random(-10, 10);
|
||
lightersSpeed[1U][i] = random(-10, 10);
|
||
lightersColor[i] = CHSV(random(0U, 255U), 255U, 255U);
|
||
}
|
||
}
|
||
FastLED.clear();
|
||
if (++loopCounter > 20U) loopCounter = 0U;
|
||
for (uint8_t i = 0U; i < modes[EFF_LIGHTERS].Scale; i++)
|
||
{
|
||
if (loopCounter == 0U) // меняем скорость каждые 255 отрисовок
|
||
{
|
||
lightersSpeed[0U][i] += random(-3, 4);
|
||
lightersSpeed[1U][i] += random(-3, 4);
|
||
lightersSpeed[0U][i] = constrain(lightersSpeed[0U][i], -20, 20);
|
||
lightersSpeed[1U][i] = constrain(lightersSpeed[1U][i], -20, 20);
|
||
}
|
||
|
||
lightersPos[0U][i] += lightersSpeed[0U][i];
|
||
lightersPos[1U][i] += lightersSpeed[1U][i];
|
||
|
||
if (lightersPos[0U][i] < 0) lightersPos[0U][i] = (WIDTH - 1) * 10;
|
||
if (lightersPos[0U][i] >= (int32_t)(WIDTH * 10)) lightersPos[0U][i] = 0;
|
||
|
||
if (lightersPos[1U][i] < 0)
|
||
{
|
||
lightersPos[1U][i] = 0;
|
||
lightersSpeed[1U][i] = -lightersSpeed[1U][i];
|
||
}
|
||
if (lightersPos[1U][i] >= (int32_t)(HEIGHT - 1) * 10)
|
||
{
|
||
lightersPos[1U][i] = (HEIGHT - 1U) * 10;
|
||
lightersSpeed[1U][i] = -lightersSpeed[1U][i];
|
||
}
|
||
drawPixelXY(lightersPos[0U][i] / 10, lightersPos[1U][i] / 10, lightersColor[i]);
|
||
}
|
||
}
|
||
|
||
// ------------- светлячки со шлейфом -------------
|
||
#define BALLS_AMOUNT (3U) // количество "шариков"
|
||
#define CLEAR_PATH (1U) // очищать путь
|
||
#define BALL_TRACK (1U) // (0 / 1) - вкл/выкл следы шариков
|
||
#define TRACK_STEP (70U) // длина хвоста шарика (чем больше цифра, тем хвост короче)
|
||
int16_t coord[BALLS_AMOUNT][2U];
|
||
int8_t vector[BALLS_AMOUNT][2U];
|
||
CRGB ballColors[BALLS_AMOUNT];
|
||
void ballsRoutine()
|
||
{
|
||
if (loadingFlag)
|
||
{
|
||
loadingFlag = false;
|
||
|
||
for (uint8_t j = 0U; j < BALLS_AMOUNT; j++)
|
||
{
|
||
int8_t sign;
|
||
// забиваем случайными данными
|
||
coord[j][0U] = WIDTH / 2 * 10;
|
||
random(0, 2) ? sign = 1 : sign = -1;
|
||
vector[j][0U] = random(4, 15) * sign;
|
||
coord[j][1U] = HEIGHT / 2 * 10;
|
||
random(0, 2) ? sign = 1 : sign = -1;
|
||
vector[j][1U] = random(4, 15) * sign;
|
||
ballColors[j] = CHSV(random(0, 9) * 28, 255U, 255U);
|
||
}
|
||
}
|
||
|
||
if (!BALL_TRACK) // режим без следов шариков
|
||
{
|
||
FastLED.clear();
|
||
}
|
||
else // режим со следами
|
||
{
|
||
fader(TRACK_STEP);
|
||
}
|
||
|
||
// движение шариков
|
||
for (uint8_t j = 0U; j < BALLS_AMOUNT; j++)
|
||
{
|
||
// движение шариков
|
||
for (uint8_t i = 0U; i < 2U; i++)
|
||
{
|
||
coord[j][i] += vector[j][i];
|
||
if (coord[j][i] < 0)
|
||
{
|
||
coord[j][i] = 0;
|
||
vector[j][i] = -vector[j][i];
|
||
}
|
||
}
|
||
|
||
if (coord[j][0U] > (int16_t)((WIDTH - 1) * 10))
|
||
{
|
||
coord[j][0U] = (WIDTH - 1) * 10;
|
||
vector[j][0U] = -vector[j][0U];
|
||
}
|
||
if (coord[j][1U] > (int16_t)((HEIGHT - 1) * 10))
|
||
{
|
||
coord[j][1U] = (HEIGHT - 1) * 10;
|
||
vector[j][1U] = -vector[j][1U];
|
||
}
|
||
leds[getPixelNumber(coord[j][0U] / 10, coord[j][1U] / 10)] = ballColors[j];
|
||
}
|
||
}
|
||
|
||
// ------------- пейнтбол -------------
|
||
const uint8_t BorderWidth = 2U;
|
||
void lightBallsRoutine()
|
||
{
|
||
// Apply some blurring to whatever's already on the matrix
|
||
// Note that we never actually clear the matrix, we just constantly
|
||
// blur it repeatedly. Since the blurring is 'lossy', there's
|
||
// an automatic trend toward black -- by design.
|
||
uint8_t blurAmount = dim8_raw(beatsin8(3,64,100));
|
||
blur2d(leds, WIDTH, HEIGHT, blurAmount);
|
||
|
||
// Use two out-of-sync sine waves
|
||
uint8_t i = beatsin8( 91, BorderWidth, WIDTH-BorderWidth);
|
||
uint8_t j = beatsin8( 109, BorderWidth, WIDTH-BorderWidth);
|
||
uint8_t k = beatsin8( 73, BorderWidth, WIDTH-BorderWidth);
|
||
uint8_t m = beatsin8( 123, BorderWidth, WIDTH-BorderWidth);
|
||
|
||
// The color of each point shifts over time, each at a different speed.
|
||
uint16_t ms = millis();
|
||
leds[XY( i, j)] += CHSV( ms / 29, 200U, 255U);
|
||
leds[XY( j, k)] += CHSV( ms / 41, 200U, 255U);
|
||
leds[XY( k, m)] += CHSV( ms / 73, 200U, 255U);
|
||
leds[XY( m, i)] += CHSV( ms / 97, 200U, 255U);
|
||
|
||
}
|
||
// Trivial XY function for the SmartMatrix; use a different XY
|
||
// function for different matrix grids. See XYMatrix example for code.
|
||
uint16_t XY(uint8_t x, uint8_t y)
|
||
{
|
||
uint16_t i;
|
||
if (y & 0x01)
|
||
{
|
||
// Odd rows run backwards
|
||
uint8_t reverseX = (WIDTH - 1) - x;
|
||
i = (y * WIDTH) + reverseX;
|
||
}
|
||
else
|
||
{
|
||
// Even rows run forwards
|
||
i = (y * WIDTH) + x;
|
||
}
|
||
return i;
|
||
}
|
||
|
||
// ------------- блуждающий кубик -------------
|
||
#define RANDOM_COLOR (1U) // случайный цвет при отскоке
|
||
int16_t coordB[2U];
|
||
int8_t vectorB[2U];
|
||
CRGB ballColor;
|
||
int8_t ballSize;
|
||
void ballRoutine()
|
||
{
|
||
if (loadingFlag)
|
||
{
|
||
loadingFlag = false;
|
||
//FastLED.clear();
|
||
|
||
for (uint8_t i = 0U; i < 2U; i++)
|
||
{
|
||
coordB[i] = WIDTH / 2 * 10;
|
||
vectorB[i] = random(8, 20);
|
||
ballColor = CHSV(random(0, 9) * 28, 255U, 255U);
|
||
}
|
||
}
|
||
|
||
ballSize = map(modes[EFF_CUBE].Scale, 0U, 255U, 2U, max((uint8_t)min(WIDTH,HEIGHT) / 3, 2));
|
||
for (uint8_t i = 0U; i < 2U; i++)
|
||
{
|
||
coordB[i] += vectorB[i];
|
||
if (coordB[i] < 0)
|
||
{
|
||
coordB[i] = 0;
|
||
vectorB[i] = -vectorB[i];
|
||
if (RANDOM_COLOR) ballColor = CHSV(random(0, 9) * 28, 255U, 255U);
|
||
//vectorB[i] += random(0, 6) - 3;
|
||
}
|
||
}
|
||
if (coordB[0U] > (int16_t)((WIDTH - ballSize) * 10))
|
||
{
|
||
coordB[0U] = (WIDTH - ballSize) * 10;
|
||
vectorB[0U] = -vectorB[0U];
|
||
if (RANDOM_COLOR) ballColor = CHSV(random(0, 9) * 28, 255U, 255U);
|
||
//vectorB[0] += random(0, 6) - 3;
|
||
}
|
||
if (coordB[1U] > (int16_t)((HEIGHT - ballSize) * 10))
|
||
{
|
||
coordB[1U] = (HEIGHT - ballSize) * 10;
|
||
vectorB[1U] = -vectorB[1U];
|
||
if (RANDOM_COLOR)
|
||
{
|
||
ballColor = CHSV(random(0, 9) * 28, 255U, 255U);
|
||
}
|
||
//vectorB[1] += random(0, 6) - 3;
|
||
}
|
||
FastLED.clear();
|
||
for (uint8_t i = 0U; i < ballSize; i++)
|
||
{
|
||
for (uint8_t j = 0U; j < ballSize; j++)
|
||
{
|
||
leds[getPixelNumber(coordB[0U] / 10 + i, coordB[1U] / 10 + j)] = ballColor;
|
||
}
|
||
}
|
||
}
|
||
|
||
// ------------- белый свет -------------
|
||
void whiteColorRoutine()
|
||
{
|
||
if (loadingFlag)
|
||
{
|
||
loadingFlag = false;
|
||
FastLED.clear();
|
||
|
||
for (uint16_t i = 0U; i < NUM_LEDS; i++)
|
||
{
|
||
leds[i] = CHSV(0U, 0U, 255U);
|
||
}
|
||
}
|
||
}
|
||
|
||
// ------------- белый свет (светится горизонтальная полоса по центру лампы; масштаб - высота центральной горизонтальной полосы; скорость - регулировка от холодного к тёплому; яркость - общая яркость) -------------
|
||
void whiteColorStripeRoutine()
|
||
{
|
||
if (loadingFlag)
|
||
{
|
||
loadingFlag = false;
|
||
FastLED.clear();
|
||
delay(1);
|
||
|
||
uint8_t centerY = max((uint8_t)round(HEIGHT / 2.0F) - 1, 0);
|
||
uint8_t bottomOffset = (uint8_t)(!(HEIGHT & 1) && (HEIGHT > 1)); // если высота матрицы чётная, линий с максимальной яркостью две, а линии с минимальной яркостью снизу будут смещены на один ряд
|
||
for (int16_t y = centerY; y >= 0; y--)
|
||
{
|
||
CRGB color = CHSV(
|
||
45U, // определяем тон
|
||
map(modes[EFF_WHITE_COLOR].Speed, 0U, 255U, 0U, 170U), // определяем насыщенность
|
||
y == centerY // определяем яркость
|
||
? 255U // для центральной горизонтальной полосы (или двух) яркость всегда равна 255
|
||
: (modes[EFF_WHITE_COLOR].Scale / 100.0F) > ((centerY + 1.0F) - (y + 1.0F)) / (centerY + 1.0F) ? 255U : 0U); // для остальных горизонтальных полос яркость равна либо 255, либо 0 в зависимости от масштаба
|
||
|
||
for (uint8_t x = 0U; x < WIDTH; x++)
|
||
{
|
||
drawPixelXY(x, y, color); // при чётной высоте матрицы максимально яркими отрисуются 2 центральных горизонтальных полосы
|
||
drawPixelXY(x, max((uint8_t)(HEIGHT - 1U) - (y + 1U) + bottomOffset, 0U), color); // при нечётной - одна, но дважды
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// ------------- мигающий цвет (не эффект! используется для отображения краткосрочного предупреждения; блокирующий код!) -------------
|
||
#define WARNING_BRIGHTNESS (10U) // яркость вспышки
|
||
void showWarning(
|
||
CRGB color, /* цвет вспышки */
|
||
uint32_t duration, /* продолжительность отображения предупреждения (общее время) */
|
||
uint16_t blinkHalfPeriod) /* продолжительность одной вспышки в миллисекундах (полупериод) */
|
||
{
|
||
uint32_t blinkTimer = millis();
|
||
enum BlinkState { OFF = 0, ON = 1 } blinkState = BlinkState::OFF;
|
||
FastLED.setBrightness(WARNING_BRIGHTNESS); // установка яркости для предупреждения
|
||
FastLED.clear();
|
||
delay(2);
|
||
FastLED.show();
|
||
|
||
for (uint16_t i = 0U; i < NUM_LEDS; i++) // установка цвета всех диодов в WARNING_COLOR
|
||
{
|
||
leds[i] = color;
|
||
}
|
||
|
||
uint32_t startTime = millis();
|
||
while (millis() - startTime <= (duration + 5)) // блокировка дальнейшего выполнения циклом на время отображения предупреждения
|
||
{
|
||
if (millis() - blinkTimer >= blinkHalfPeriod) // переключение вспышка/темнота
|
||
{
|
||
blinkTimer = millis();
|
||
blinkState = (BlinkState)!blinkState;
|
||
FastLED.setBrightness(blinkState == BlinkState::OFF ? 0 : WARNING_BRIGHTNESS);
|
||
delay(1);
|
||
FastLED.show();
|
||
}
|
||
delay(50);
|
||
}
|
||
|
||
FastLED.clear();
|
||
FastLED.setBrightness(ONflag ? modes[currentMode].Brightness : 0); // установка яркости, которая была выставлена до вызова предупреждения
|
||
delay(1);
|
||
FastLED.show();
|
||
loadingFlag = true; // принудительное отображение текущего эффекта (того, что был активен перед предупреждением)
|
||
}
|