ESP32-HUB75-MatrixPanel-DMA/examples/ChainedPanelsAuroraDemo/Effects.h

914 lines
27 KiB
C++

/*
Aurora: https://github.com/pixelmatix/aurora
Copyright (c) 2014 Jason Coon
Portions of this code are adapted from "Funky Clouds" by Stefan Petrick: https://gist.github.com/anonymous/876f908333cd95315c35
Portions of this code are adapted from "NoiseSmearing" by Stefan Petrick: https://gist.github.com/StefanPetrick/9ee2f677dbff64e3ba7a
Copyright (c) 2014 Stefan Petrick
http://www.stefan-petrick.de/wordpress_beta
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef Effects_H
#define Effects_H
/* ---------------------------- GLOBAL CONSTANTS ----------------------------- */
//const int MATRIX_CENTER_X = MATRIX_WIDTH / 2;
//const int MATRIX_CENTER_Y = MATRIX_HEIGHT / 2;
//const byte MATRIX_CENTRE_X = MATRIX_CENTER_X - 1;
//const byte MATRIX_CENTRE_Y = MATRIX_CENTER_Y - 1;
const int MATRIX_CENTER_X = VPANEL_W / 2;
const int MATRIX_CENTER_Y = VPANEL_H / 2;
const byte MATRIX_CENTRE_X = MATRIX_CENTER_X - 1;
const byte MATRIX_CENTRE_Y = MATRIX_CENTER_Y - 1;
const uint16_t NUM_LEDS = (VPANEL_W * VPANEL_H) + 1; // one led spare to capture out of bounds
/* Convert x,y co-ordinate to flat array index.
x and y positions start from 0, so must not be >= 'real' panel width or height
(i.e. 64 pixels or 32 pixels.). Max value: MATRIX_WIDTH-1 etc.
*/
uint16_t XY( uint8_t x, uint8_t y)
{
if ( x >= VPANEL_W || x < 0) return 0;
if ( y >= VPANEL_H || y < 0) return 0;
return (y * VPANEL_W) + x + 1; // everything offset by one to capture out of bounds stuff - never displayed by ShowFrame()
}
/// Some mathematics provided by FastLED
uint8_t beatcos8(accum88 beats_per_minute, uint8_t lowest = 0, uint8_t highest = 255, uint32_t timebase = 0, uint8_t phase_offset = 0)
{
uint8_t beat = beat8(beats_per_minute, timebase);
uint8_t beatcos = cos8(beat + phase_offset);
uint8_t rangewidth = highest - lowest;
uint8_t scaledbeat = scale8(beatcos, rangewidth);
uint8_t result = lowest + scaledbeat;
return result;
}
uint8_t mapsin8(uint8_t theta, uint8_t lowest = 0, uint8_t highest = 255) {
uint8_t beatsin = sin8(theta);
uint8_t rangewidth = highest - lowest;
uint8_t scaledbeat = scale8(beatsin, rangewidth);
uint8_t result = lowest + scaledbeat;
return result;
}
uint8_t mapcos8(uint8_t theta, uint8_t lowest = 0, uint8_t highest = 255) {
uint8_t beatcos = cos8(theta);
uint8_t rangewidth = highest - lowest;
uint8_t scaledbeat = scale8(beatcos, rangewidth);
uint8_t result = lowest + scaledbeat;
return result;
}
// Array of temperature readings at each simulation cell
byte heat[NUM_LEDS];
uint32_t noise_x;
uint32_t noise_y;
uint32_t noise_z;
uint32_t noise_scale_x;
uint32_t noise_scale_y;
uint8_t noise[VPANEL_W][VPANEL_H];
uint8_t noisesmoothing;
class Effects {
public:
//CRGB *leds;
CRGB leds[NUM_LEDS];
CRGB leds2[NUM_LEDS]; // Faptastic: getting rid of this and any dependant effects or algos. to save memory 24*64*32 bytes of ram (50k).
/* The only 'framebuffer' we have is what is contained in the leds and leds2 variables.
We don't store what the color a particular pixel might be, other than when it's turned
into raw electrical signal output gobbly-gook (i.e. the DMA matrix buffer), but this * is not reversible.
As such, any time these effects want to write a pixel color, we first have to update
the leds or leds2 array, and THEN write it to the RGB panel. This enables us to 'look up' the array to see what a pixel color was previously, each drawFrame().
*/
void drawBackgroundFastLEDPixelCRGB(int16_t x, int16_t y, CRGB color)
{
leds[XY(x, y)] = color;
virtualDisp.drawPixelRGB888(x, y, color.r, color.g, color.b);
}
// write one pixel with the specified color from the current palette to coordinates
void Pixel(int x, int y, uint8_t colorIndex) {
CRGB temp = ColorFromCurrentPalette(colorIndex);
leds[XY(x, y)] = temp;
virtualDisp.drawPixelRGB888(x, y, temp.r, temp.g, temp.b); // now draw it?
}
void PrepareFrame() {
// leds = (CRGB*) backgroundLayer.backBuffer();
}
void ShowFrame() {
#if (FASTLED_VERSION >= 3001000)
nblendPaletteTowardPalette(currentPalette, targetPalette, 24);
#else
currentPalette = targetPalette;
#endif
// backgroundLayer.swapBuffers();
// leds = (CRGB*) backgroundLayer.backBuffer();
// LEDS.countFPS();
for (int y = 0; y < VPANEL_H; y++) {
for (int x = 0; x < VPANEL_W; x++)
{
CRGB tmp_led = leds[XY(x, y)];
virtualDisp.drawPixelRGB888( x, y, tmp_led.r, tmp_led.g, tmp_led.b);
} // end loop to copy fast led to the dma matrix
}
}
// scale the brightness of the screenbuffer down
void DimAll(byte value)
{
for (int i = 0; i < NUM_LEDS; i++)
{
leds[i].nscale8(value);
}
}
void ClearFrame()
{
memset(leds, 0x00, sizeof(leds)); // flush
}
void CircleStream(uint8_t value) {
DimAll(value); ShowFrame();
for (uint8_t offset = 0; offset < MATRIX_CENTER_X; offset++) {
boolean hasprev = false;
uint16_t prevxy = 0;
for (uint8_t theta = 0; theta < 255; theta++) {
uint8_t x = mapcos8(theta, offset, (VPANEL_W - 1) - offset);
uint8_t y = mapsin8(theta, offset, (VPANEL_H - 1) - offset);
uint16_t xy = XY(x, y);
if (hasprev) {
leds[prevxy] += leds[xy];
}
prevxy = xy;
hasprev = true;
}
}
for (uint8_t x = 0; x < VPANEL_W; x++) {
for (uint8_t y = 0; y < VPANEL_H; y++) {
uint16_t xy = XY(x, y);
leds[xy] = leds2[xy];
leds[xy].nscale8(value);
leds2[xy].nscale8(value);
}
}
}
// palettes
static const int paletteCount = 10;
int paletteIndex = -1;
TBlendType currentBlendType = LINEARBLEND;
CRGBPalette16 currentPalette;
CRGBPalette16 targetPalette;
char* currentPaletteName;
static const int HeatColorsPaletteIndex = 6;
static const int RandomPaletteIndex = 9;
void Setup() {
currentPalette = RainbowColors_p;
loadPalette(0);
NoiseVariablesSetup();
}
void CyclePalette(int offset = 1) {
loadPalette(paletteIndex + offset);
}
void RandomPalette() {
loadPalette(RandomPaletteIndex);
}
void loadPalette(int index) {
paletteIndex = index;
if (paletteIndex >= paletteCount)
paletteIndex = 0;
else if (paletteIndex < 0)
paletteIndex = paletteCount - 1;
switch (paletteIndex) {
case 0:
targetPalette = RainbowColors_p;
currentPaletteName = (char *)"Rainbow";
break;
case 1:
targetPalette = OceanColors_p;
currentPaletteName = (char *)"Ocean";
break;
case 2:
targetPalette = CloudColors_p;
currentPaletteName = (char *)"Cloud";
break;
case 3:
targetPalette = ForestColors_p;
currentPaletteName = (char *)"Forest";
break;
case 4:
targetPalette = PartyColors_p;
currentPaletteName = (char *)"Party";
break;
case 5:
setupGrayscalePalette();
currentPaletteName = (char *)"Grey";
break;
case HeatColorsPaletteIndex:
targetPalette = HeatColors_p;
currentPaletteName = (char *)"Heat";
break;
case 7:
targetPalette = LavaColors_p;
currentPaletteName = (char *)"Lava";
break;
case 8:
setupIcePalette();
currentPaletteName = (char *)"Ice";
break;
case RandomPaletteIndex:
loadPalette(random(0, paletteCount - 1));
paletteIndex = RandomPaletteIndex;
currentPaletteName = (char *)"Random";
break;
}
}
void setPalette(String paletteName) {
if (paletteName == "Rainbow")
loadPalette(0);
else if (paletteName == "Ocean")
loadPalette(1);
else if (paletteName == "Cloud")
loadPalette(2);
else if (paletteName == "Forest")
loadPalette(3);
else if (paletteName == "Party")
loadPalette(4);
else if (paletteName == "Grayscale")
loadPalette(5);
else if (paletteName == "Heat")
loadPalette(6);
else if (paletteName == "Lava")
loadPalette(7);
else if (paletteName == "Ice")
loadPalette(8);
else if (paletteName == "Random")
RandomPalette();
}
void listPalettes() {
Serial.println(F("{"));
Serial.print(F(" \"count\": "));
Serial.print(paletteCount);
Serial.println(",");
Serial.println(F(" \"results\": ["));
String paletteNames [] = {
"Rainbow",
// "RainbowStripe",
"Ocean",
"Cloud",
"Forest",
"Party",
"Grayscale",
"Heat",
"Lava",
"Ice",
"Random"
};
for (int i = 0; i < paletteCount; i++) {
Serial.print(F(" \""));
Serial.print(paletteNames[i]);
if (i == paletteCount - 1)
Serial.println(F("\""));
else
Serial.println(F("\","));
}
Serial.println(" ]");
Serial.println("}");
}
void setupGrayscalePalette() {
targetPalette = CRGBPalette16(CRGB::Black, CRGB::White);
}
void setupIcePalette() {
targetPalette = CRGBPalette16(CRGB::Black, CRGB::Blue, CRGB::Aqua, CRGB::White);
}
// Oscillators and Emitters
// the oscillators: linear ramps 0-255
byte osci[6];
// sin8(osci) swinging between 0 to MATRIX_WIDTH - 1
byte p[6];
// set the speeds (and by that ratios) of the oscillators here
void MoveOscillators() {
osci[0] = osci[0] + 5;
osci[1] = osci[1] + 2;
osci[2] = osci[2] + 3;
osci[3] = osci[3] + 4;
osci[4] = osci[4] + 1;
if (osci[4] % 2 == 0)
osci[5] = osci[5] + 1; // .5
for (int i = 0; i < 4; i++) {
p[i] = map8(sin8(osci[i]), 0, VPANEL_W - 1); //why? to keep the result in the range of 0-MATRIX_WIDTH (matrix size)
}
}
// All the caleidoscope functions work directly within the screenbuffer (leds array).
// Draw whatever you like in the area x(0-15) and y (0-15) and then copy it arround.
// rotates the first 16x16 quadrant 3 times onto a 32x32 (+90 degrees rotation for each one)
void Caleidoscope1() {
for (int x = 0; x < MATRIX_CENTER_X; x++) {
for (int y = 0; y < MATRIX_CENTER_Y; y++) {
leds[XY(VPANEL_W - 1 - x, y)] = leds[XY(x, y)];
leds[XY(VPANEL_W - 1 - x, VPANEL_H - 1 - y)] = leds[XY(x, y)];
leds[XY(x, VPANEL_H - 1 - y)] = leds[XY(x, y)];
}
}
}
// mirror the first 16x16 quadrant 3 times onto a 32x32
void Caleidoscope2() {
for (int x = 0; x < MATRIX_CENTER_X; x++) {
for (int y = 0; y < MATRIX_CENTER_Y; y++) {
leds[XY(VPANEL_W - 1 - x, y)] = leds[XY(y, x)];
leds[XY(x, VPANEL_H - 1 - y)] = leds[XY(y, x)];
leds[XY(VPANEL_W - 1 - x, VPANEL_H - 1 - y)] = leds[XY(x, y)];
}
}
}
// copy one diagonal triangle into the other one within a 16x16
void Caleidoscope3() {
for (int x = 0; x <= MATRIX_CENTRE_X; x++) {
for (int y = 0; y <= x; y++) {
leds[XY(x, y)] = leds[XY(y, x)];
}
}
}
// copy one diagonal triangle into the other one within a 16x16 (90 degrees rotated compared to Caleidoscope3)
void Caleidoscope4() {
for (int x = 0; x <= MATRIX_CENTRE_X; x++) {
for (int y = 0; y <= MATRIX_CENTRE_Y - x; y++) {
leds[XY(MATRIX_CENTRE_Y - y, MATRIX_CENTRE_X - x)] = leds[XY(x, y)];
}
}
}
// copy one diagonal triangle into the other one within a 8x8
void Caleidoscope5() {
for (int x = 0; x < VPANEL_W / 4; x++) {
for (int y = 0; y <= x; y++) {
leds[XY(x, y)] = leds[XY(y, x)];
}
}
for (int x = VPANEL_W / 4; x < VPANEL_W / 2; x++) {
for (int y = VPANEL_H / 4; y >= 0; y--) {
leds[XY(x, y)] = leds[XY(y, x)];
}
}
}
void Caleidoscope6() {
for (int x = 1; x < MATRIX_CENTER_X; x++) {
leds[XY(7 - x, 7)] = leds[XY(x, 0)];
} //a
for (int x = 2; x < MATRIX_CENTER_X; x++) {
leds[XY(7 - x, 6)] = leds[XY(x, 1)];
} //b
for (int x = 3; x < MATRIX_CENTER_X; x++) {
leds[XY(7 - x, 5)] = leds[XY(x, 2)];
} //c
for (int x = 4; x < MATRIX_CENTER_X; x++) {
leds[XY(7 - x, 4)] = leds[XY(x, 3)];
} //d
for (int x = 5; x < MATRIX_CENTER_X; x++) {
leds[XY(7 - x, 3)] = leds[XY(x, 4)];
} //e
for (int x = 6; x < MATRIX_CENTER_X; x++) {
leds[XY(7 - x, 2)] = leds[XY(x, 5)];
} //f
for (int x = 7; x < MATRIX_CENTER_X; x++) {
leds[XY(7 - x, 1)] = leds[XY(x, 6)];
} //g
}
// create a square twister to the left or counter-clockwise
// x and y for center, r for radius
void SpiralStream(int x, int y, int r, byte dimm) {
for (int d = r; d >= 0; d--) { // from the outside to the inside
for (int i = x - d; i <= x + d; i++) {
leds[XY(i, y - d)] += leds[XY(i + 1, y - d)]; // lowest row to the right
leds[XY(i, y - d)].nscale8(dimm);
}
for (int i = y - d; i <= y + d; i++) {
leds[XY(x + d, i)] += leds[XY(x + d, i + 1)]; // right colum up
leds[XY(x + d, i)].nscale8(dimm);
}
for (int i = x + d; i >= x - d; i--) {
leds[XY(i, y + d)] += leds[XY(i - 1, y + d)]; // upper row to the left
leds[XY(i, y + d)].nscale8(dimm);
}
for (int i = y + d; i >= y - d; i--) {
leds[XY(x - d, i)] += leds[XY(x - d, i - 1)]; // left colum down
leds[XY(x - d, i)].nscale8(dimm);
}
}
}
// expand everything within a circle
void Expand(int centerX, int centerY, int radius, byte dimm) {
if (radius == 0)
return;
int currentRadius = radius;
while (currentRadius > 0) {
int a = radius, b = 0;
int radiusError = 1 - a;
int nextRadius = currentRadius - 1;
int nextA = nextRadius - 1, nextB = 0;
int nextRadiusError = 1 - nextA;
while (a >= b)
{
// move them out one pixel on the radius
leds[XY(a + centerX, b + centerY)] = leds[XY(nextA + centerX, nextB + centerY)];
leds[XY(b + centerX, a + centerY)] = leds[XY(nextB + centerX, nextA + centerY)];
leds[XY(-a + centerX, b + centerY)] = leds[XY(-nextA + centerX, nextB + centerY)];
leds[XY(-b + centerX, a + centerY)] = leds[XY(-nextB + centerX, nextA + centerY)];
leds[XY(-a + centerX, -b + centerY)] = leds[XY(-nextA + centerX, -nextB + centerY)];
leds[XY(-b + centerX, -a + centerY)] = leds[XY(-nextB + centerX, -nextA + centerY)];
leds[XY(a + centerX, -b + centerY)] = leds[XY(nextA + centerX, -nextB + centerY)];
leds[XY(b + centerX, -a + centerY)] = leds[XY(nextB + centerX, -nextA + centerY)];
// dim them
leds[XY(a + centerX, b + centerY)].nscale8(dimm);
leds[XY(b + centerX, a + centerY)].nscale8(dimm);
leds[XY(-a + centerX, b + centerY)].nscale8(dimm);
leds[XY(-b + centerX, a + centerY)].nscale8(dimm);
leds[XY(-a + centerX, -b + centerY)].nscale8(dimm);
leds[XY(-b + centerX, -a + centerY)].nscale8(dimm);
leds[XY(a + centerX, -b + centerY)].nscale8(dimm);
leds[XY(b + centerX, -a + centerY)].nscale8(dimm);
b++;
if (radiusError < 0)
radiusError += 2 * b + 1;
else
{
a--;
radiusError += 2 * (b - a + 1);
}
nextB++;
if (nextRadiusError < 0)
nextRadiusError += 2 * nextB + 1;
else
{
nextA--;
nextRadiusError += 2 * (nextB - nextA + 1);
}
}
currentRadius--;
}
}
// give it a linear tail to the right
void StreamRight(byte scale, int fromX = 0, int toX = VPANEL_W, int fromY = 0, int toY = VPANEL_H)
{
for (int x = fromX + 1; x < toX; x++) {
for (int y = fromY; y < toY; y++) {
leds[XY(x, y)] += leds[XY(x - 1, y)];
leds[XY(x, y)].nscale8(scale);
}
}
for (int y = fromY; y < toY; y++)
leds[XY(0, y)].nscale8(scale);
}
// give it a linear tail to the left
void StreamLeft(byte scale, int fromX = VPANEL_W, int toX = 0, int fromY = 0, int toY = VPANEL_H)
{
for (int x = toX; x < fromX; x++) {
for (int y = fromY; y < toY; y++) {
leds[XY(x, y)] += leds[XY(x + 1, y)];
leds[XY(x, y)].nscale8(scale);
}
}
for (int y = fromY; y < toY; y++)
leds[XY(0, y)].nscale8(scale);
}
// give it a linear tail downwards
void StreamDown(byte scale)
{
for (int x = 0; x < VPANEL_W; x++) {
for (int y = 1; y < VPANEL_H; y++) {
leds[XY(x, y)] += leds[XY(x, y - 1)];
leds[XY(x, y)].nscale8(scale);
}
}
for (int x = 0; x < VPANEL_W; x++)
leds[XY(x, 0)].nscale8(scale);
}
// give it a linear tail upwards
void StreamUp(byte scale)
{
for (int x = 0; x < VPANEL_W; x++) {
for (int y = VPANEL_H - 2; y >= 0; y--) {
leds[XY(x, y)] += leds[XY(x, y + 1)];
leds[XY(x, y)].nscale8(scale);
}
}
for (int x = 0; x < VPANEL_W; x++)
leds[XY(x, VPANEL_H - 1)].nscale8(scale);
}
// give it a linear tail up and to the left
void StreamUpAndLeft(byte scale)
{
for (int x = 0; x < VPANEL_W - 1; x++) {
for (int y = VPANEL_H - 2; y >= 0; y--) {
leds[XY(x, y)] += leds[XY(x + 1, y + 1)];
leds[XY(x, y)].nscale8(scale);
}
}
for (int x = 0; x < VPANEL_W; x++)
leds[XY(x, VPANEL_H - 1)].nscale8(scale);
for (int y = 0; y < VPANEL_H; y++)
leds[XY(VPANEL_W - 1, y)].nscale8(scale);
}
// give it a linear tail up and to the right
void StreamUpAndRight(byte scale)
{
for (int x = 0; x < VPANEL_W - 1; x++) {
for (int y = VPANEL_H - 2; y >= 0; y--) {
leds[XY(x + 1, y)] += leds[XY(x, y + 1)];
leds[XY(x, y)].nscale8(scale);
}
}
// fade the bottom row
for (int x = 0; x < VPANEL_W; x++)
leds[XY(x, VPANEL_H - 1)].nscale8(scale);
// fade the right column
for (int y = 0; y < VPANEL_H; y++)
leds[XY(VPANEL_W - 1, y)].nscale8(scale);
}
// just move everything one line down
void MoveDown() {
for (int y = VPANEL_H - 1; y > 0; y--) {
for (int x = 0; x < VPANEL_W; x++) {
leds[XY(x, y)] = leds[XY(x, y - 1)];
}
}
}
// just move everything one line down
void VerticalMoveFrom(int start, int end) {
for (int y = end; y > start; y--) {
for (int x = 0; x < VPANEL_W; x++) {
leds[XY(x, y)] = leds[XY(x, y - 1)];
}
}
}
// copy the rectangle defined with 2 points x0, y0, x1, y1
// to the rectangle beginning at x2, x3
void Copy(byte x0, byte y0, byte x1, byte y1, byte x2, byte y2) {
for (int y = y0; y < y1 + 1; y++) {
for (int x = x0; x < x1 + 1; x++) {
leds[XY(x + x2 - x0, y + y2 - y0)] = leds[XY(x, y)];
}
}
}
// rotate + copy triangle (MATRIX_CENTER_X*MATRIX_CENTER_X)
void RotateTriangle() {
for (int x = 1; x < MATRIX_CENTER_X; x++) {
for (int y = 0; y < x; y++) {
leds[XY(x, 7 - y)] = leds[XY(7 - x, y)];
}
}
}
// mirror + copy triangle (MATRIX_CENTER_X*MATRIX_CENTER_X)
void MirrorTriangle() {
for (int x = 1; x < MATRIX_CENTER_X; x++) {
for (int y = 0; y < x; y++) {
leds[XY(7 - y, x)] = leds[XY(7 - x, y)];
}
}
}
// draw static rainbow triangle pattern (MATRIX_CENTER_XxWIDTH / 2)
// (just for debugging)
void RainbowTriangle() {
for (int i = 0; i < MATRIX_CENTER_X; i++) {
for (int j = 0; j <= i; j++) {
Pixel(7 - i, j, i * j * 4);
}
}
}
void BresenhamLine(int x0, int y0, int x1, int y1, byte colorIndex)
{
BresenhamLine(x0, y0, x1, y1, ColorFromCurrentPalette(colorIndex));
}
void BresenhamLine(int x0, int y0, int x1, int y1, CRGB color)
{
int dx = abs(x1 - x0), sx = x0 < x1 ? 1 : -1;
int dy = -abs(y1 - y0), sy = y0 < y1 ? 1 : -1;
int err = dx + dy, e2;
for (;;) {
leds[XY(x0, y0)] += color;
if (x0 == x1 && y0 == y1) break;
e2 = 2 * err;
if (e2 > dy) {
err += dy;
x0 += sx;
}
if (e2 < dx) {
err += dx;
y0 += sy;
}
}
}
// write one pixel with the specified color from the current palette to coordinates
/*
void Pixel(int x, int y, uint8_t colorIndex) {
leds[XY(x, y)] = ColorFromCurrentPalette(colorIndex);
matrix.drawBackgroundPixelRGB888(x,y, leds[XY(x, y)]); // now draw it?
}
*/
CRGB ColorFromCurrentPalette(uint8_t index = 0, uint8_t brightness = 255, TBlendType blendType = LINEARBLEND) {
return ColorFromPalette(currentPalette, index, brightness, currentBlendType);
}
CRGB HsvToRgb(uint8_t h, uint8_t s, uint8_t v) {
CHSV hsv = CHSV(h, s, v);
CRGB rgb;
hsv2rgb_spectrum(hsv, rgb);
return rgb;
}
void NoiseVariablesSetup() {
noisesmoothing = 200;
noise_x = random16();
noise_y = random16();
noise_z = random16();
noise_scale_x = 6000;
noise_scale_y = 6000;
}
void FillNoise() {
for (uint8_t i = 0; i < VPANEL_W; i++) {
uint32_t ioffset = noise_scale_x * (i - MATRIX_CENTRE_Y);
for (uint8_t j = 0; j < VPANEL_H; j++) {
uint32_t joffset = noise_scale_y * (j - MATRIX_CENTRE_Y);
byte data = inoise16(noise_x + ioffset, noise_y + joffset, noise_z) >> 8;
uint8_t olddata = noise[i][j];
uint8_t newdata = scale8(olddata, noisesmoothing) + scale8(data, 256 - noisesmoothing);
data = newdata;
noise[i][j] = data;
}
}
}
// non leds2 memory version.
void MoveX(byte delta)
{
CRGB tmp = 0;
for (int y = 0; y < VPANEL_H; y++)
{
// Shift Left: https://codedost.com/c/arraypointers-in-c/c-program-shift-elements-array-left-direction/
// Computationally heavier but doesn't need an entire leds2 array
tmp = leds[XY(0, y)];
for (int m = 0; m < delta; m++)
{
// Do this delta time for each row... computationally expensive potentially.
for (int x = 0; x < VPANEL_H; x++)
{
leds[XY(x, y)] = leds [XY(x + 1, y)];
}
leds[XY(VPANEL_W - 1, y)] = tmp;
}
/*
// Shift
for (int x = 0; x < VPANEL_W - delta; x++) {
leds2[XY(x, y)] = leds[XY(x + delta, y)];
}
// Wrap around
for (int x = VPANEL_W - delta; x < VPANEL_W; x++) {
leds2[XY(x, y)] = leds[XY(x + delta - VPANEL_H, y)];
}
*/
} // end row loop
/*
// write back to leds
for (uint8_t y = 0; y < VPANEL_H; y++) {
for (uint8_t x = 0; x < VPANEL_W; x++) {
leds[XY(x, y)] = leds2[XY(x, y)];
}
}
*/
}
void MoveY(byte delta)
{
CRGB tmp = 0;
for (int x = 0; x < VPANEL_W; x++)
{
tmp = leds[XY(x, 0)];
for (int m = 0; m < delta; m++) // moves
{
// Do this delta time for each row... computationally expensive potentially.
for (int y = 0; y < VPANEL_H; y++)
{
leds[XY(x, y)] = leds [XY(x, y + 1)];
}
leds[XY(x, VPANEL_H - 1)] = tmp;
}
} // end column loop
} /// MoveY
void MoveFractionalNoiseX(byte amt = 16) {
// move delta pixelwise
for (int y = 0; y < VPANEL_H; y++) {
uint16_t amount = noise[0][y] * amt;
byte delta = 31 - (amount / 256);
for (int x = 0; x < VPANEL_W - delta; x++) {
leds2[XY(x, y)] = leds[XY(x + delta, y)];
}
for (int x = VPANEL_H - delta; x < VPANEL_W; x++) {
leds2[XY(x, y)] = leds[XY(x + delta - VPANEL_W, y)];
}
}
//move fractions
CRGB PixelA;
CRGB PixelB;
for (uint8_t y = 0; y < VPANEL_H; y++) {
uint16_t amount = noise[0][y] * amt;
byte delta = 31 - (amount / 256);
byte fractions = amount - (delta * 256);
for (uint8_t x = 1; x < VPANEL_W; x++) {
PixelA = leds2[XY(x, y)];
PixelB = leds2[XY(x - 1, y)];
PixelA %= 255 - fractions;
PixelB %= fractions;
leds[XY(x, y)] = PixelA + PixelB;
}
PixelA = leds2[XY(0, y)];
PixelB = leds2[XY(VPANEL_W - 1, y)];
PixelA %= 255 - fractions;
PixelB %= fractions;
leds[XY(0, y)] = PixelA + PixelB;
}
}
void MoveFractionalNoiseY(byte amt = 16) {
// move delta pixelwise
for (int x = 0; x < VPANEL_W; x++) {
uint16_t amount = noise[x][0] * amt;
byte delta = 31 - (amount / 256);
for (int y = 0; y < VPANEL_W - delta; y++) {
leds2[XY(x, y)] = leds[XY(x, y + delta)];
}
for (int y = VPANEL_W - delta; y < VPANEL_W; y++) {
leds2[XY(x, y)] = leds[XY(x, y + delta - VPANEL_W)];
}
}
//move fractions
CRGB PixelA;
CRGB PixelB;
for (uint8_t x = 0; x < VPANEL_H; x++) {
uint16_t amount = noise[x][0] * amt;
byte delta = 31 - (amount / 256);
byte fractions = amount - (delta * 256);
for (uint8_t y = 1; y < VPANEL_W; y++) {
PixelA = leds2[XY(x, y)];
PixelB = leds2[XY(x, y - 1)];
PixelA %= 255 - fractions;
PixelB %= fractions;
leds[XY(x, y)] = PixelA + PixelB;
}
PixelA = leds2[XY(x, 0)];
PixelB = leds2[XY(x, VPANEL_W - 1)];
PixelA %= 255 - fractions;
PixelB %= fractions;
leds[XY(x, 0)] = PixelA + PixelB;
}
}
void standardNoiseSmearing() {
noise_x += 1000;
noise_y += 1000;
noise_scale_x = 4000;
noise_scale_y = 4000;
FillNoise();
MoveX(3);
MoveFractionalNoiseY(4);
MoveY(3);
MoveFractionalNoiseX(4);
}
};
#endif