/*
* 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
#define MAX_COLOR_VALUE 255
#define SWAPint(X,Y) { \
int temp = X ; \
X = Y ; \
Y = temp ; \
}
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 beattriwave8(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 = triwave8(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[MatrixWidth][MatrixHeight];
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[MatrixWidth][MatrixHeight];
uint8_t noisesmoothing;
// Oscillators and Emitters
// the oscillators: linear ramps 0-255
byte osci[6];
// sin8(osci) swinging between 0 to MatrixWidth - 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, MatrixWidth - 1); //why? to keep the result in the range of 0-MatrixWidth (matrix size)
}
}
// scale the brightness of the screenbuffer down
void DimAll(byte value)
{
for (int i = 0; i < NUM_LEDS; i++)
{
leds[i].nscale8(value);
}
}
// give it a linear tail to the right
void StreamRight(byte scale, int fromX = 0, int toX = MatrixWidth, int fromY = 0, int toY = MatrixHeight)
{
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 = MatrixWidth, int toX = 0, int fromY = 0, int toY = MatrixHeight)
{
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 < MatrixWidth; x++) {
for (int y = 1; y < MatrixHeight; y++) {
leds[XY(x, y)] += leds[XY(x, y - 1)];
leds[XY(x, y)].nscale8(scale);
}
}
for (int x = 0; x < MatrixWidth; x++)
leds[XY(x, 0)].nscale8(scale);
}
// give it a linear tail upwards
void StreamUp(byte scale)
{
for (int x = 0; x < MatrixWidth; x++) {
for (int y = MatrixHeight - 2; y >= 0; y--) {
leds[XY(x, y)] += leds[XY(x, y + 1)];
leds[XY(x, y)].nscale8(scale);
}
}
for (int x = 0; x < MatrixWidth; x++)
leds[XY(x, MatrixHeight - 1)].nscale8(scale);
}
// give it a linear tail up and to the left
void StreamUpAndLeft(byte scale)
{
for (int x = 0; x < MatrixWidth - 1; x++) {
for (int y = MatrixHeight - 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 < MatrixWidth; x++)
leds[XY(x, MatrixHeight - 1)].nscale8(scale);
for (int y = 0; y < MatrixHeight; y++)
leds[XY(MatrixWidth - 1, y)].nscale8(scale);
}
// give it a linear tail up and to the right
void StreamUpAndRight(byte scale)
{
for (int x = 0; x < MatrixWidth - 1; x++) {
for (int y = MatrixHeight - 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 < MatrixWidth; x++)
leds[XY(x, MatrixHeight - 1)].nscale8(scale);
// fade the right column
for (int y = 0; y < MatrixHeight; y++)
leds[XY(MatrixWidth - 1, y)].nscale8(scale);
}
// just move everything one line down
void MoveDown() {
for (int y = MatrixHeight - 1; y > 0; y--) {
for (int x = 0; x < MatrixWidth; 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 < MatrixWidth; x++) {
leds[XY(x, y)] = leds[XY(x, y - 1)];
}
}
}
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;
}
}
}
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 < MatrixWidth; i++) {
uint32_t ioffset = noise_scale_x * (i - MATRIX_CENTRE_Y);
for (uint8_t j = 0; j < MatrixHeight; 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;
}
}
}
void MoveX(byte delta) {
for (int y = 0; y < MatrixHeight; y++) {
for (int x = 0; x < MatrixWidth - delta; x++) {
leds2[XY(x, y)] = leds[XY(x + delta, y)];
}
for (int x = MatrixWidth - delta; x < MatrixWidth; x++) {
leds2[XY(x, y)] = leds[XY(x + delta - MatrixWidth, y)];
}
}
// write back to leds
for (uint8_t y = 0; y < MatrixHeight; y++) {
for (uint8_t x = 0; x < MatrixWidth; x++) {
leds[XY(x, y)] = leds2[XY(x, y)];
}
}
}
void MoveY(byte delta) {
for (int x = 0; x < MatrixWidth; x++) {
for (int y = 0; y < MatrixHeight - delta; y++) {
leds2[XY(x, y)] = leds[XY(x, y + delta)];
}
for (int y = MatrixHeight - delta; y < MatrixHeight; y++) {
leds2[XY(x, y)] = leds[XY(x, y + delta - MatrixHeight)];
}
}
// write back to leds
for (uint8_t y = 0; y < MatrixHeight; y++) {
for (uint8_t x = 0; x < MatrixWidth; x++) {
leds[XY(x, y)] = leds2[XY(x, y)];
}
}
}
void MoveFractionalNoiseX(byte amt = 16) {
// move delta pixelwise
for (int y = 0; y < MatrixHeight; y++) {
uint16_t amount = noise[0][y] * amt;
byte delta = 31 - (amount / 256);
for (int x = 0; x < MatrixWidth - delta; x++) {
leds2[XY(x, y)] = leds[XY(x + delta, y)];
}
for (int x = MatrixWidth - delta; x < MatrixWidth; x++) {
leds2[XY(x, y)] = leds[XY(x + delta - MatrixWidth, y)];
}
}
//move fractions
CRGB PixelA;
CRGB PixelB;
for (uint8_t y = 0; y < MatrixHeight; y++) {
uint16_t amount = noise[0][y] * amt;
byte delta = 31 - (amount / 256);
byte fractions = amount - (delta * 256);
for (uint8_t x = 1; x < MatrixWidth; 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(MatrixWidth - 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 < MatrixWidth; x++) {
uint16_t amount = noise[x][0] * amt;
byte delta = 31 - (amount / 256);
for (int y = 0; y < MatrixWidth - delta; y++) {
leds2[XY(x, y)] = leds[XY(x, y + delta)];
}
for (int y = MatrixWidth - delta; y < MatrixWidth; y++) {
leds2[XY(x, y)] = leds[XY(x, y + delta - MatrixWidth)];
}
}
//move fractions
CRGB PixelA;
CRGB PixelB;
for (uint8_t x = 0; x < MatrixHeight; x++) {
uint16_t amount = noise[x][0] * amt;
byte delta = 31 - (amount / 256);
byte fractions = amount - (delta * 256);
for (uint8_t y = 1; y < MatrixWidth; 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, MatrixWidth - 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