Topology, Curves, Gamma, and Samples

Topology, Tiles, and Mosaic layout
Animation Curves
Color Gamma correct
change timescale dynamically on NeoPixelAnimator
bilinear color blend methods
new samples to support new features
This commit is contained in:
Makuna
2016-03-20 10:06:58 -07:00
parent 22f5e71a0b
commit 3dbfae7fc4
30 changed files with 1917 additions and 110 deletions

View File

@@ -8,6 +8,7 @@ A library to control one wire protocol RGB and RGBW leds like SK6812, WS2811, an
Supports most Arduino platforms.
This is the most funtional library for the Esp8266 as it provides solutions for all Esp8266 module types even when WiFi is used.
Please read this best practices link before connecting your NeoPixels, it will save you alot of time and effort.
[Adafruit NeoPixel Best Practices](https://learn.adafruit.com/adafruit-neopixel-uberguide/best-practices)
@@ -16,21 +17,18 @@ For quick questions jump on Gitter and ask away.
For bugs, make sure there isn't an active issue and then create one.
This new library supports a templatized model of defining which method gets used to send data and what order and size the pixel data is sent in. This new design creates the smallest code for each definition of features used. Further it allows for picking which method to send the data on the Esp8266 in an easy to change way.
Please see examples to become familiar with the new design.
Due to this design you will often realize over 500 bytes of more program storage for your sketch. Important for the smallest Arduinos project.
## Documentation
[See Wiki](https://github.com/Makuna/NeoPixelBus/wiki)
## Installing This Library (prefered)
## Installing This Library (prefered, you just want to use it)
Open the Library Manager and search for "NeoPixelBus by Makuna" and install
## Installing This Library From GitHub
## Installing This Library From GitHub (advanced, you want to contribute)
Create a directory in your Arduino\Library folder named "NeoPixelBus"
Clone (Git) this project into that folder.
It should now show up in the import list when you restart Arduino IDE.
## Documentation
[See Wiki](https://github.com/Makuna/NeoPixelBus/wiki)

View File

@@ -0,0 +1,121 @@
// NeoPixelCylon
// This example will move a Cylong Red Eye back and forth across the
// the full collection of pixels on the strip.
//
// This will demonstrate the use of the NeoEase animation ease methods; that provide
// simulated acceleration to the animations.
//
//
#include <NeoPixelBus.h>
#include <NeoPixelAnimator.h>
const uint16_t PixelCount = 16; // make sure to set this to the number of pixels in your strip
const uint8_t PixelPin = 2; // make sure to set this to the correct pin, ignored for Esp8266
const RgbColor CylonEyeColor(HtmlColor(0x7f0000));
NeoPixelBus<NeoGrbFeature, Neo800KbpsMethod> strip(PixelCount, PixelPin);
NeoPixelAnimator animations(2); // only ever need 2 animations
uint16_t lastPixel = 0; // track the eye position
int8_t moveDir = 1; // track the direction of movement
// uncomment one of the lines below to see the effects of
// changing the ease function on the movement animation
AnimEaseFunction moveEase =
// NeoEase::Linear;
// NeoEase::QuadraticInOut;
// NeoEase::CubicInOut;
NeoEase::QuarticInOut;
// NeoEase::QuinticInOut;
// NeoEase::SinusoidalInOut;
// NeoEase::ExponentialInOut;
// NeoEase::CircularInOut;
void FadeAll(uint8_t darkenBy)
{
RgbColor color;
for (uint16_t indexPixel = 0; indexPixel < strip.PixelCount(); indexPixel++)
{
color = strip.GetPixelColor(indexPixel);
color.Darken(darkenBy);
strip.SetPixelColor(indexPixel, color);
}
}
void FadeAnimUpdate(const AnimationParam& param)
{
if (param.state == AnimationState_Completed)
{
FadeAll(10);
animations.RestartAnimation(param.index);
}
}
void MoveAnimUpdate(const AnimationParam& param)
{
// apply the movement animation curve
float progress = moveEase(param.progress);
// use the curved progress to calculate the pixel to effect
uint16_t nextPixel;
if (moveDir > 0)
{
nextPixel = progress * PixelCount;
}
else
{
nextPixel = (1.0f - progress) * PixelCount;
}
// if progress moves fast enough, we may move more than
// one pixel, so we update all between the calculated and
// the last
if (lastPixel != nextPixel)
{
for (uint16_t i = lastPixel + moveDir; i != nextPixel; i += moveDir)
{
strip.SetPixelColor(i, CylonEyeColor);
}
}
strip.SetPixelColor(nextPixel, CylonEyeColor);
lastPixel = nextPixel;
if (param.state == AnimationState_Completed)
{
// reverse direction of movement
moveDir *= -1;
// done, time to restart this position tracking animation/timer
animations.RestartAnimation(param.index);
}
}
void SetupAnimations()
{
// fade all pixels providing a tail that is longer the faster
// the pixel moves.
animations.StartAnimation(0, 5, FadeAnimUpdate);
// take several seconds to move eye fron one side to the other
animations.StartAnimation(1, 2000, MoveAnimUpdate);
}
void setup()
{
strip.Begin();
strip.Show();
SetupAnimations();
}
void loop()
{
// this is all that is needed to keep it running
// and avoiding using delay() is always a good thing for
// any timing related routines
animations.UpdateAnimations();
strip.Show();
}

View File

@@ -0,0 +1,93 @@
// NeoPixelGamma
// This example will display a timed series of color gradiants with gamma correction
// and then without.
// If the last pixel is on, then the colors being shown are color corrected.
// It will show Red grandiant, Green grandiant, Blue grandiant, a White grandiant, and
// then repeat.
//
// This will demonstrate the use of the NeoGamma class
//
//
#include <NeoPixelBus.h>
#include <NeoPixelAnimator.h>
const uint16_t PixelCount = 16; // make sure to set this to the number of pixels in your strip
const uint8_t PixelPin = 2; // make sure to set this to the correct pin, ignored for Esp8266
NeoPixelBus<NeoGrbFeature, Neo800KbpsMethod> strip(PixelCount, PixelPin);
// uncomment only one of these to compare memory use or speed
//
// NeoGamma<NeoGammaEquationMethod> gamma;
NeoGamma<NeoGammaTableMethod> gamma;
void DrawPixels(bool corrected, HslColor startColor, HslColor stopColor)
{
for (uint16_t index = 0; index < strip.PixelCount() - 1; index++)
{
float progress = index / static_cast<float>(strip.PixelCount() - 2);
RgbColor color = HslColor::LinearBlend(startColor, stopColor, progress);
if (corrected)
{
color = gamma.Correct(color);
}
strip.SetPixelColor(index, color);
}
// use the last pixel to indicate if we are showing corrected colors or not
if (corrected)
{
strip.SetPixelColor(strip.PixelCount() - 1, RgbColor(64));
}
else
{
strip.SetPixelColor(strip.PixelCount() - 1, RgbColor(0));
}
strip.Show();
}
void setup()
{
strip.Begin();
strip.Show();
}
void loop()
{
HslColor startColor;
HslColor stopColor;
// red color
startColor = HslColor(0.0f, 1.0f, 0.0f);
stopColor = HslColor(0.0f, 1.0f, 0.5f);
DrawPixels(true, startColor, stopColor);
delay(5000);
DrawPixels(false, startColor, stopColor);
delay(5000);
// green color
startColor = HslColor(0.33f, 1.0f, 0.0f);
stopColor = HslColor(0.33f, 1.0f, 0.5f);
DrawPixels(true, startColor, stopColor);
delay(5000);
DrawPixels(false, startColor, stopColor);
delay(5000);
// blue color
startColor = HslColor(0.66f, 1.0f, 0.0f);
stopColor = HslColor(0.66f, 1.0f, 0.5f);
DrawPixels(true, startColor, stopColor);
delay(5000);
DrawPixels(false, startColor, stopColor);
delay(5000);
// white color
startColor = HslColor(0.0f, 0.0f, 0.0f);
stopColor = HslColor(0.0f, 0.0f, 0.5f);
DrawPixels(true, startColor, stopColor);
delay(5000);
DrawPixels(false, startColor, stopColor);
delay(5000);
}

View File

@@ -0,0 +1,98 @@
//----------------------------------------------------------------------
// NeoPixelMosaicDump
// This will dump to the serial output a grid map of the defined mosaic
// The output is displayed as row column labeled grid with the NeoPixelBus
// index of the pixel at the intersection of the row and column.
//
// To help with physical layout, there maybe included a symbol following the index
// < means the index is the input index for the panel, the first on the panel
// > means the index is the output index for the panel, the last on the panel
//
// This is useful in visualising the mosaic layout of your panels to
// confirm you have them correctly wired together for this mosaic pattern
//
// It does not require that you have the actual panel connected
//----------------------------------------------------------------------
#include <NeoPixelAnimator.h>
#include <NeoPixelBus.h>
// uncomment one of these that matches your panel pixel layouts
// rotation is ignored for mosaic as it applies a rotation for you
// that is specific to the location of the panel within the mosaic
// to reduce connection lengths
typedef ColumnMajorAlternatingLayout MyPanelLayout;
// typedef ColumnMajorLayout MyPanelLayout;
// typedef RowMajorAlternatingLayout MyPanelLayout;
// typedef RowMajorLayout MyPanelLayout;
// make sure to set these panel and tile layout to match your sizes
const uint8_t PanelWidth = 8; // a 8 pixel x 8 pixel matrix of leds on the panel
const uint8_t PanelHeight = 8;
const uint8_t TileWidth = 4; // laid out in 4 panels x 2 panels mosaic
const uint8_t TileHeight = 2;
NeoMosaic <MyPanelLayout> mosaic(
PanelWidth,
PanelHeight,
TileWidth,
TileHeight);
void DumpMosaic()
{
Serial.println();
Serial.print("\t\t");
for (int x = 0; x < mosaic.getWidth(); x++)
{
Serial.print(x);
Serial.print("\t");
}
Serial.println();
Serial.print("\t---");
for (int x = 0; x < mosaic.getWidth(); x++)
{
Serial.print("--------");
}
Serial.println();
for (int y = 0; y < mosaic.getHeight(); y++)
{
Serial.print(" ");
Serial.print(y);
Serial.print("\t|\t");
for (int x = 0; x < mosaic.getWidth(); x++)
{
NeoTopologyHint hint = mosaic.TopologyHint(x, y);
Serial.print(mosaic.Map(x, y));
if (hint == NeoTopologyHint_FirstOnPanel)
{
Serial.print("<");
}
else if (hint == NeoTopologyHint_LastOnPanel)
{
Serial.print(">");
}
Serial.print("\t");
}
Serial.println();
}
}
void setup()
{
Serial.begin(115200);
while (!Serial); // wait for serial attach
DumpMosaic();
}
void loop()
{
}

View File

@@ -0,0 +1,97 @@
//----------------------------------------------------------------------
// NeoPixelTopologyTest
// This will display specific colors in specific locations on the led panels
//
// This is useful in confirming the layout of your panels
//
// It does require that you have the actual panels connected
//----------------------------------------------------------------------
#include <NeoPixelAnimator.h>
#include <NeoPixelBus.h>
// uncomment one of these that matches your panel pixel layouts
// rotation is ignored for mosaic as it applies a rotation for you
// that is specific to the location of the panel within the mosaic
// to reduce connection lengths
typedef ColumnMajorAlternatingLayout MyPanelLayout;
// typedef ColumnMajorLayout MyPanelLayout;
// typedef RowMajorAlternatingLayout MyPanelLayout;
// typedef RowMajorLayout MyPanelLayout;
// make sure to set these panel values to the sizes of yours
const uint8_t PanelWidth = 8; // 8 pixel x 8 pixel matrix of leds
const uint8_t PanelHeight = 8;
const uint8_t TileWidth = 4; // laid out in 4 panels x 2 panels mosaic
const uint8_t TileHeight = 2;
const uint16_t PixelCount = PanelWidth * PanelHeight * TileWidth * TileHeight;
const uint8_t PixelPin = 2;
NeoMosaic <MyPanelLayout> mosaic(
PanelWidth,
PanelHeight,
TileWidth,
TileHeight);
NeoPixelBus<NeoGrbFeature, Neo800KbpsMethod> strip(PixelCount, PixelPin);
//NeoPixelBus<NeoRgbFeature, Neo800KbpsMethod> strip(PixelCount, PixelPin);
//NeoPixelBus<NeoRgbwFeature, Neo800KbpsMethod> strip(PixelCount, PixelPin);
RgbColor red(128, 0, 0);
RgbColor green(0, 128, 0);
RgbColor blue(0, 0, 128);
RgbColor white(128);
// if using NeoRgbwFeature above, use this white instead to use
// the correct white element of the LED
//RgbwColor white(128);
RgbColor black(0);
const uint16_t left = 0;
const uint16_t right = PanelWidth - 1;
const uint16_t top = 0;
const uint16_t bottom = PanelHeight - 1;
void setup()
{
Serial.begin(115200);
while (!Serial); // wait for serial attach
Serial.println();
Serial.println("Initializing...");
strip.Begin();
strip.Show();
Serial.println();
Serial.println("Running...");
}
void loop()
{
delay(2500);
Serial.println();
Serial.println("If your panel is correctly defined, you should see ...");
Serial.println("Upper left is white.");
Serial.println("Upper right is Red.");
Serial.println("Lower right is Green");
Serial.println("Lower Left is Blue");
// use the topo to map the 2d cordinate to the pixel
// and use that to SetPixelColor
strip.SetPixelColor(mosaic.Map(left, top), white);
strip.SetPixelColor(mosaic.Map(right, top), red);
strip.SetPixelColor(mosaic.Map(right, bottom), green);
strip.SetPixelColor(mosaic.Map(left, bottom), blue);
strip.Show();
delay(5000);
Serial.println();
Serial.println("Cleared to black ...");
strip.ClearTo(black);
strip.Show();
}

View File

@@ -0,0 +1,102 @@
//----------------------------------------------------------------------
// NeoPixelTileDump
// This will dump to the serial output a grid map of the defined tiles
// The output is displayed as row column labeled grid with the NeoPixelBus
// index of the pixel at the intersection of the row and column
//
// To help with physical layout, there maybe included a symbol following the index
// < means the index is the input index for the panel, the first on the panel
// > means the index is the output index for the panel, the last on the panel
//
// This is useful in visualising the tile layout of your panels to
// confirm you have them correctly wired together for the defined pattern
//
// It does not require that you have the actual panel connected
//----------------------------------------------------------------------
#include <NeoPixelAnimator.h>
#include <NeoPixelBus.h>
// uncomment one of these that matches your panel pixel layouts and
// how you want them rotated. Not all the rotations are listed here
// but you can modifiy the name to include the rotation of 90,180, or 270.
typedef ColumnMajorAlternatingLayout MyPanelLayout;
// typedef ColumnMajorLayout MyPanelLayout;
// typedef RowMajorAlternatingLayout MyPanelLayout;
// typedef RowMajorLayout MyPanelLayout;
// typedef RowMajor90Layout MyPanelLayout; // note rotation 90 was used
// change this to be one of the layouts which will define the layout
// of the panels themselves
typedef ColumnMajorLayout MyTilesLayout;
// make sure to set these panel and tile layout to match your sizes
const uint8_t PanelWidth = 8; // 8 pixel x 8 pixel matrix of leds
const uint8_t PanelHeight = 8;
const uint8_t TileWidth = 4; // laid out in 4 panels x 2 panels mosaic
const uint8_t TileHeight = 2;
NeoTiles <MyPanelLayout, MyTilesLayout> tiles(
PanelWidth,
PanelHeight,
TileWidth,
TileHeight);
void DumpTopo()
{
Serial.println();
Serial.print("\t\t");
for (int x = 0; x < tiles.getWidth(); x++)
{
Serial.print(x);
Serial.print("\t");
}
Serial.println();
Serial.print("\t---");
for (int x = 0; x < tiles.getWidth(); x++)
{
Serial.print("--------");
}
Serial.println();
for (int y = 0; y < tiles.getHeight(); y++)
{
Serial.print(" ");
Serial.print(y);
Serial.print("\t|\t");
for (int x = 0; x < tiles.getWidth(); x++)
{
NeoTopologyHint hint = tiles.TopologyHint(x, y);
Serial.print(tiles.Map(x, y));
if (hint == NeoTopologyHint_FirstOnPanel)
{
Serial.print("<");
}
else if (hint == NeoTopologyHint_LastOnPanel)
{
Serial.print(">");
}
Serial.print("\t");
}
Serial.println();
}
}
void setup()
{
Serial.begin(115200);
while (!Serial); // wait for serial attach
DumpTopo();
}
void loop()
{
}

View File

@@ -0,0 +1,101 @@
//----------------------------------------------------------------------
// NeoPixelTilesTest
// This will display specific colors in specific locations on the led panels
//
// This is useful in confirming the layout of your panels
//
// It does require that you have the actual panels connected
//----------------------------------------------------------------------
#include <NeoPixelAnimator.h>
#include <NeoPixelBus.h>
// uncomment one of these that matches your panel pixel layouts and
// how you want them rotated. Not all the rotations are listed here
// but you can modifiy the name to include the rotation of 90,180, or 270.
typedef ColumnMajorAlternatingLayout MyPanelLayout;
// typedef ColumnMajorLayout MyPanelLayout;
// typedef RowMajorAlternatingLayout MyPanelLayout;
// typedef RowMajorLayout MyPanelLayout;
// typedef RowMajor90Layout MyPanelLayout; // note rotation 90 was used
// change this to be one of the layouts which will define the layout
// of the panels themselves
typedef ColumnMajorLayout MyTilesLayout;
// make sure to set these panel values to the sizes of yours
const uint8_t PanelWidth = 8; // 8 pixel x 8 pixel matrix of leds
const uint8_t PanelHeight = 8;
const uint8_t TileWidth = 4; // laid out in 4 panels x 2 panels mosaic
const uint8_t TileHeight = 2;
const uint16_t PixelCount = PanelWidth * PanelHeight * TileWidth * TileHeight;
const uint8_t PixelPin = 2;
NeoTiles <MyPanelLayout, MyTilesLayout> tiles(
PanelWidth,
PanelHeight,
TileWidth,
TileHeight);
NeoPixelBus<NeoGrbFeature, Neo800KbpsMethod> strip(PixelCount, PixelPin);
//NeoPixelBus<NeoRgbFeature, Neo800KbpsMethod> strip(PixelCount, PixelPin);
//NeoPixelBus<NeoRgbwFeature, Neo800KbpsMethod> strip(PixelCount, PixelPin);
RgbColor red(128, 0, 0);
RgbColor green(0, 128, 0);
RgbColor blue(0, 0, 128);
RgbColor white(128);
// if using NeoRgbwFeature above, use this white instead to use
// the correct white element of the LED
//RgbwColor white(128);
RgbColor black(0);
const uint16_t left = 0;
const uint16_t right = PanelWidth - 1;
const uint16_t top = 0;
const uint16_t bottom = PanelHeight - 1;
void setup()
{
Serial.begin(115200);
while (!Serial); // wait for serial attach
Serial.println();
Serial.println("Initializing...");
strip.Begin();
strip.Show();
Serial.println();
Serial.println("Running...");
}
void loop()
{
delay(2500);
Serial.println();
Serial.println("If your panel is correctly defined, you should see ...");
Serial.println("Upper left is white.");
Serial.println("Upper right is Red.");
Serial.println("Lower right is Green");
Serial.println("Lower Left is Blue");
// use the topo to map the 2d cordinate to the pixel
// and use that to SetPixelColor
strip.SetPixelColor(tiles.Map(left, top), white);
strip.SetPixelColor(tiles.Map(right, top), red);
strip.SetPixelColor(tiles.Map(right, bottom), green);
strip.SetPixelColor(tiles.Map(left, bottom), blue);
strip.Show();
delay(5000);
Serial.println();
Serial.println("Cleared to black ...");
strip.ClearTo(black);
strip.Show();
}

View File

@@ -0,0 +1,78 @@
//----------------------------------------------------------------------
// NeoPixelTopologyDump
// This will dump to the serial output a grid map of the defined topology
// The output is displayed as row column labeled grid with the NeoPixelBus
// index of the pixel at the intersection of the row and column
//
// This is useful in visualising the layout of your panel so you can
// confirm you have the correct pattern
//
// It does not require that you have the actual panel connected
//----------------------------------------------------------------------
#include <NeoPixelAnimator.h>
#include <NeoPixelBus.h>
// uncomment one of these that matches your panel pixel layouts and
// how you want them rotated. Not all the rotations are listed here
// but you can modifiy the name to include the rotation of 90,180, or 270.
typedef ColumnMajorAlternatingLayout MyPanelLayout;
// typedef ColumnMajorLayout MyPanelLayout;
// typedef RowMajorAlternatingLayout MyPanelLayout;
// typedef RowMajorLayout MyPanelLayout;
// typedef RowMajor90Layout MyPanelLayout; // note rotation 90 was used
// make sure to set these panel values to the sizes of yours
const uint8_t PanelWidth = 8; // 8 pixel x 8 pixel matrix of leds
const uint8_t PanelHeight = 8;
NeoTopology<MyPanelLayout> topo(PanelWidth, PanelHeight);
void DumpTopo()
{
Serial.println();
Serial.print("\t\t");
for (int x = 0; x < topo.getWidth(); x++)
{
Serial.print(x);
Serial.print("\t");
}
Serial.println();
Serial.print("\t--");
for (int x = 0; x < topo.getWidth(); x++)
{
Serial.print("--------");
}
Serial.println();
for (int y = 0; y < topo.getHeight(); y++)
{
Serial.print(" ");
Serial.print(y);
Serial.print("\t|\t");
for (int x = 0; x < topo.getWidth(); x++)
{
Serial.print(topo.Map(x, y));
Serial.print("\t");
}
Serial.println();
}
}
void setup()
{
Serial.begin(115200);
while (!Serial); // wait for serial attach
DumpTopo();
}
void loop()
{
}

View File

@@ -0,0 +1,90 @@
//----------------------------------------------------------------------
// NeoPixelTopologyTest
// This will display specific colors in specific locations on the led panel
//
// This is useful in confirming the layout of your panel
//
// It does require that you have the actual panel connected
//----------------------------------------------------------------------
#include <NeoPixelAnimator.h>
#include <NeoPixelBus.h>
// uncomment one of these that matches your panel pixel layouts and
// how you want them rotated. Not all the rotations are listed here
// but you can modifiy the name to include the rotation of 90,180, or 270.
typedef ColumnMajorAlternatingLayout MyPanelLayout;
// typedef ColumnMajorLayout MyPanelLayout;
// typedef RowMajorAlternatingLayout MyPanelLayout;
// typedef RowMajorLayout MyPanelLayout;
// typedef RowMajor90Layout MyPanelLayout; // note rotation 90 was used
// make sure to set these panel values to the sizes of yours
const uint8_t PanelWidth = 8; // 8 pixel x 8 pixel matrix of leds
const uint8_t PanelHeight = 8;
const uint16_t PixelCount = PanelWidth * PanelHeight;
const uint8_t PixelPin = 2; // make sure to set this to the correct pin, ignored for Esp8266
NeoTopology<MyPanelLayout> topo(PanelWidth, PanelHeight);
NeoPixelBus<NeoGrbFeature, Neo800KbpsMethod> strip(PixelCount, PixelPin);
//NeoPixelBus<NeoRgbFeature, Neo800KbpsMethod> strip(PixelCount, PixelPin);
//NeoPixelBus<NeoRgbwFeature, Neo800KbpsMethod> strip(PixelCount, PixelPin);
RgbColor red(128, 0, 0);
RgbColor green(0, 128, 0);
RgbColor blue(0, 0, 128);
RgbColor white(128);
// if using NeoRgbwFeature above, use this white instead to use
// the correct white element of the LED
//RgbwColor white(128);
RgbColor black(0);
const uint16_t left = 0;
const uint16_t right = PanelWidth - 1;
const uint16_t top = 0;
const uint16_t bottom = PanelHeight - 1;
void setup()
{
Serial.begin(115200);
while (!Serial); // wait for serial attach
Serial.println();
Serial.println("Initializing...");
strip.Begin();
strip.Show();
Serial.println();
Serial.println("Running...");
}
void loop()
{
delay(2500);
Serial.println();
Serial.println("If your panel is correctly defined, you should see ...");
Serial.println("Upper left is white.");
Serial.println("Upper right is Red.");
Serial.println("Lower right is Green");
Serial.println("Lower Left is Blue");
// use the topo to map the 2d cordinate to the pixel
// and use that to SetPixelColor
strip.SetPixelColor(topo.Map(left, top), white);
strip.SetPixelColor(topo.Map(right, top), red);
strip.SetPixelColor(topo.Map(right, bottom), green);
strip.SetPixelColor(topo.Map(left, bottom), blue);
strip.Show();
delay(5000);
Serial.println();
Serial.println("Cleared to black ...");
strip.ClearTo(black);
strip.Show();
}

View File

@@ -31,6 +31,28 @@ AnimUpdateCallback KEYWORD1
AnimationParam KEYWORD1
NeoEase KEYWORD1
AnimEaseFunction KEYWORD1
RowMajorLayout KEYWORD1
RowMajor90Layout KEYWORD1
RowMajor180Layout KEYWORD1
RowMajor270Layout KEYWORD1
RowMajorAlternatingLayout KEYWORD1
RowMajorAlternating90Layout KEYWORD1
RowMajorAlternating180Layout KEYWORD1
RowMajorAlternating270Layout KEYWORD1
ColumnMajorLayout KEYWORD1
ColumnMajor90Layout KEYWORD1
ColumnMajor180Layout KEYWORD1
ColumnMajor270Layout KEYWORD1
ColumnMajorAlternatingLayout KEYWORD1
ColumnMajorAlternating90Layout KEYWORD1
ColumnMajorAlternating180Layout KEYWORD1
ColumnMajorAlternating270Layout KEYWORD1
NeoTopology KEYWORD1
NeoTiles KEYWORD1
NeoMosaic KEYWORD1
NeoGammaEquationMethod KEYWORD1
NeoGammaTableMethod KEYWORD1
NeoGamma KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
@@ -52,6 +74,7 @@ CalculateBrightness KEYWORD2
Darken KEYWORD2
Lighten KEYWORD2
LinearBlend KEYWORD2
BilinearBlend KEYWORD2
IsAnimating KEYWORD2
NextAvailableAnimation KEYWORD2
StartAnimation KEYWORD2
@@ -63,7 +86,8 @@ UpdateAnimations KEYWORD2
IsPaused KEYWORD2
Pause KEYWORD2
Resume KEYWORD2
TimeScale KEYWORD2
getTimeScale KEYWORD2
setTimeScale KEYWORD2
QuadraticIn KEYWORD2
QuadraticOut KEYWORD2
QuadraticInOut KEYWORD2
@@ -85,6 +109,12 @@ ExponentialInOut KEYWORD2
CircularIn KEYWORD2
CircularOut KEYWORD2
CircularInOut KEYWORD2
Gamma KEYWORD2
Map KEYWORD2
getWidth KEYWORD2
getHeight KEYWORD2
TopologyHint KEYWORD2
Correct KEYWORD2
#######################################
# Constants (LITERAL1)
@@ -98,3 +128,6 @@ NEO_DECASECONDS LITERAL1
AnimationState_Started LITERAL1
AnimationState_Progress LITERAL1
AnimationState_Completed LITERAL1
NeoTopologyHint_FirstOnPanel LITERAL1
NeoTopologyHint_InPanel LITERAL1
NeoTopologyHint_LastOnPanel LITERAL1

View File

@@ -1,9 +1,9 @@
name=NeoPixelBus by Makuna
version=2.0.3
version=2.0.4
author=Michael C. Miller (makuna@live.com)
maintainer=Michael C. Miller (makuna@live.com)
sentence=A library that makes controlling NeoPixels (WS2811, WS2812 & SK6812) easy.
paragraph=Supports most Arduino platforms, and especially Esp8266. Support for RGBW pixels. Includes seperate RgbColor, RgbwColor, HslColor, and HsbColor objects. Includes an animator class that helps create asyncronous animations. For Esp8266 it has three methods of sending data, DMA, UART, and Bit Bang.
category=Display
url=https://github.com/Makuna/NeoPixelBus
url=https://github.com/Makuna/NeoPixelBus/wiki
architectures=*

View File

@@ -125,11 +125,16 @@ public:
_animationLastTick = millis();
}
uint16_t TimeScale()
uint16_t getTimeScale()
{
return _timeScale;
}
void setTimeScale(uint16_t timeScale)
{
_timeScale = (timeScale < 1) ? (1) : (timeScale > 32768) ? 32768 : timeScale;
}
private:
struct AnimationContext
{

View File

@@ -32,6 +32,15 @@ License along with NeoPixel. If not, see
#include "internal/HsbColor.h"
#include "internal/HtmlColor.h"
#include "internal/RgbwColor.h"
#include "internal/Layouts.h"
#include "internal/NeoTopology.h"
#include "internal/NeoTiles.h"
#include "internal/NeoMosaic.h"
#include "internal/NeoEase.h"
#include "internal/NeoGamma.h"
#include "internal/NeoColorFeatures.h"
#if defined(ARDUINO_ARCH_ESP8266)
@@ -124,7 +133,7 @@ public:
return _countPixels;
};
void SetPixelColor(uint16_t indexPixel, typename T_COLOR_FEATURE::ColorObject color)
void SetPixelColor(uint16_t indexPixel, const typename T_COLOR_FEATURE::ColorObject& color)
{
if (indexPixel < _countPixels)
{

View File

@@ -67,7 +67,7 @@ HsbColor::HsbColor(const RgbColor& color)
B = v;
}
HsbColor HsbColor::LinearBlend(HsbColor left, HsbColor right, float progress)
HsbColor HsbColor::LinearBlend(const HsbColor& left, const HsbColor& right, float progress)
{
return HsbColor(left.H + ((right.H - left.H) * progress),
left.S + ((right.S - left.S) * progress),

View File

@@ -1,3 +1,4 @@
/*-------------------------------------------------------------------------
HsbColor provides a color object that can be directly consumed by NeoPixelBus
@@ -62,7 +63,7 @@ struct HsbColor
// progress - (0.0 - 1.0) value where 0.0 will return left and 1.0 will return right
// and a value between will blend the color weighted linearly between them
// ------------------------------------------------------------------------
static HsbColor LinearBlend(HsbColor left, HsbColor right, float progress);
static HsbColor LinearBlend(const HsbColor& left, const HsbColor& right, float progress);
// ------------------------------------------------------------------------
// Hue, Saturation, Brightness color members

View File

@@ -1,6 +1,7 @@
/*-------------------------------------------------------------------------
HslColor provides a color object that can be directly consumed by NeoPixelBus
Written by Michael C. Miller.
I invest time and resources providing this open source code,
@@ -70,7 +71,7 @@ HslColor::HslColor(const RgbColor& color)
L = l;
}
HslColor HslColor::LinearBlend(HslColor left, HslColor right, float progress)
HslColor HslColor::LinearBlend(const HslColor& left, const HslColor& right, float progress)
{
return HslColor(left.H + ((right.H - left.H) * progress),
left.S + ((right.S - left.S) * progress),

View File

@@ -64,7 +64,7 @@ struct HslColor
// progress - (0.0 - 1.0) value where 0.0 will return left and 1.0 will return right
// and a value between will blend the color weighted linearly between them
// ------------------------------------------------------------------------
static HslColor LinearBlend(HslColor left, HslColor right, float progress);
static HslColor LinearBlend(const HslColor& left, const HslColor& right, float progress);
// ------------------------------------------------------------------------
// Hue, Saturation, Lightness color members

View File

@@ -62,6 +62,24 @@ struct HtmlColor
{
};
// ------------------------------------------------------------------------
// BilinearBlend between four colors by the amount defined by 2d variable
// c00 - upper left quadrant color
// c01 - upper right quadrant color
// c10 - lower left quadrant color
// c11 - lower right quadrant color
// x - unit value (0.0 - 1.0) that defines the blend progress in horizontal space
// y - unit value (0.0 - 1.0) that defines the blend progress in vertical space
// ------------------------------------------------------------------------
static HtmlColor BilinearBlend(const HtmlColor& c00,
const HtmlColor& c01,
const HtmlColor& c10,
const HtmlColor& c11,
float x,
float y)
{
return RgbColor::BilinearBlend(c00, c01, c10, c11, x, y);
}
// ------------------------------------------------------------------------
// Color member (0-0xffffff) where

425
src/internal/Layouts.h Normal file
View File

@@ -0,0 +1,425 @@
#pragma once
/*-------------------------------------------------------------------------
Layout provides a collection of class objects that are used with NeoTopology
object.
They define the specific layout of pixels and do the math to change the 2d
cordinate space to 1d cordinate space
Written by Michael C. Miller.
I invest time and resources providing this open source code,
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
-------------------------------------------------------------------------
This file is part of the Makuna/NeoPixelBus library.
NeoPixelBus is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
NeoPixelBus is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with NeoPixel. If not, see
<http://www.gnu.org/licenses/>.
-------------------------------------------------------------------------*/
//-----------------------------------------------------------------------------
// RowMajor
//-----------------------------------------------------------------------------
class RowMajorLayout;
class RowMajor90Layout;
class RowMajor180Layout;
class RowMajor270Layout;
class RowMajorTilePreference
{
public:
typedef RowMajorLayout EvenRowEvenColumnLayout;
typedef RowMajor270Layout EvenRowOddColumnLayout;
typedef RowMajor90Layout OddRowEvenColumnLayout;
typedef RowMajor180Layout OddRowOddColumnLayout;
};
// layout example of 4x4
// 00 01 02 03
// 04 05 06 07
// 08 09 10 11
// 12 13 14 15
//
class RowMajorLayout : public RowMajorTilePreference
{
public:
static uint16_t Map(uint16_t width, uint16_t height, uint16_t x, uint16_t y)
{
return x + y * width;
}
};
// layout example of 4x4
// 12 08 04 00
// 13 09 05 01
// 14 10 06 02
// 15 11 07 03
//
class RowMajor90Layout : public RowMajorTilePreference
{
public:
static uint16_t Map(uint16_t width, uint16_t height, uint16_t x, uint16_t y)
{
return (width - 1 - x) * height + y;
}
};
// layout example of 4x4
// 15 14 13 12
// 11 10 09 08
// 07 06 05 04
// 03 02 01 00
//
class RowMajor180Layout : public RowMajorTilePreference
{
public:
static uint16_t Map(uint16_t width, uint16_t height, uint16_t x, uint16_t y)
{
return (width - 1 - x) + (height - 1 - y) * width;
}
};
// layout example of 4x4
// 03 07 11 15
// 02 06 10 14
// 01 05 09 13
// 00 04 08 12
//
class RowMajor270Layout : public RowMajorTilePreference
{
public:
static uint16_t Map(uint16_t width, uint16_t height, uint16_t x, uint16_t y)
{
return x * height + (height - 1 - y);
}
};
//-----------------------------------------------------------------------------
// ColumnMajor
//-----------------------------------------------------------------------------
class ColumnMajorLayout;
class ColumnMajor90Layout;
class ColumnMajor180Layout;
class ColumnMajor270Layout;
class ColumnMajorTilePreference
{
public:
typedef ColumnMajorLayout EvenRowEvenColumnLayout;
typedef ColumnMajor270Layout EvenRowOddColumnLayout;
typedef ColumnMajor90Layout OddRowEvenColumnLayout;
typedef ColumnMajor180Layout OddRowOddColumnLayout;
};
// layout example of 4x4
// 00 04 08 12
// 01 05 09 13
// 02 06 10 14
// 03 07 11 15
//
class ColumnMajorLayout : public ColumnMajorTilePreference
{
public:
static uint16_t Map(uint16_t width, uint16_t height, uint16_t x, uint16_t y)
{
return x * height + y;
}
};
// layout example of 4x4
// 03 02 01 00
// 07 06 05 04
// 11 10 09 08
// 15 14 13 12
//
class ColumnMajor90Layout : public ColumnMajorTilePreference
{
public:
static uint16_t Map(uint16_t width, uint16_t height, uint16_t x, uint16_t y)
{
return (width - 1 - x) + y * width;
}
};
// layout example of 4x4
// 15 11 07 03
// 14 10 06 02
// 13 09 05 01
// 12 08 04 00
//
class ColumnMajor180Layout : public ColumnMajorTilePreference
{
public:
static uint16_t Map(uint16_t width, uint16_t height, uint16_t x, uint16_t y)
{
return (width - 1 - x) * height + (height - 1 - y);
}
};
// layout example of 4x4
// 12 13 14 15
// 08 09 10 11
// 04 05 06 07
// 00 01 02 03
//
class ColumnMajor270Layout : public ColumnMajorTilePreference
{
public:
static uint16_t Map(uint16_t width, uint16_t height, uint16_t x, uint16_t y)
{
return x + (height - 1 - y) * width;
}
};
//-----------------------------------------------------------------------------
// RowMajorAlternating
//-----------------------------------------------------------------------------
class RowMajorAlternating270Layout;
class RowMajorAlternating90Layout;
class RowMajorAlternatingTilePreference
{
public:
typedef RowMajorAlternating270Layout EvenRowEvenColumnLayout;
typedef RowMajorAlternating270Layout EvenRowOddColumnLayout;
typedef RowMajorAlternating90Layout OddRowEvenColumnLayout;
typedef RowMajorAlternating90Layout OddRowOddColumnLayout;
};
// layout example of 4x4
// 00 01 02 03
// 07 06 05 04
// 08 09 10 11
// 15 14 13 12
//
class RowMajorAlternatingLayout : public RowMajorAlternatingTilePreference
{
public:
static uint16_t Map(uint16_t width, uint16_t height, uint16_t x, uint16_t y)
{
uint16_t index = y * width;
if (y & 0x0001)
{
index += ((width - 1) - x);
}
else
{
index += x;
}
return index;
}
};
// layout example of 4x4
// 15 08 07 00
// 14 09 06 01
// 13 10 05 02
// 12 11 04 03
//
class RowMajorAlternating90Layout : public RowMajorAlternatingTilePreference
{
public:
static uint16_t Map(uint16_t width, uint16_t height, uint16_t x, uint16_t y)
{
uint16_t mx = ((width - 1) - x);
uint16_t index = mx * height;
if (mx & 0x0001)
{
index += ((height - 1) - y);
}
else
{
index += y;
}
return index;
}
};
// layout example of 4x4
// 12 13 14 15
// 11 10 09 08
// 04 05 06 07
// 03 02 01 00
//
class RowMajorAlternating180Layout : public RowMajorAlternatingTilePreference
{
public:
static uint16_t Map(uint16_t width, uint16_t height, uint16_t x, uint16_t y)
{
uint16_t my = ((height - 1) - y);
uint16_t index = my * width;
if (my & 0x0001)
{
index += x;
}
else
{
index += ((width - 1) - x);
}
return index;
}
};
// layout example of 4x4
// 03 04 11 12
// 02 05 10 13
// 01 06 09 14
// 00 07 08 15
//
class RowMajorAlternating270Layout : public RowMajorAlternatingTilePreference
{
public:
static uint16_t Map(uint16_t width, uint16_t height, uint16_t x, uint16_t y)
{
uint16_t index = x * height;
if (x & 0x0001)
{
index += y;
}
else
{
index += ((height - 1) - y);
}
return index;
}
};
//-----------------------------------------------------------------------------
// ColumnMajorAlternating
//-----------------------------------------------------------------------------
class ColumnMajorAlternatingLayout;
class ColumnMajorAlternating180Layout;
class ColumnMajorAlternatingTilePreference
{
public:
typedef ColumnMajorAlternatingLayout EvenRowEvenColumnLayout;
typedef ColumnMajorAlternatingLayout EvenRowOddColumnLayout;
typedef ColumnMajorAlternating180Layout OddRowEvenColumnLayout;
typedef ColumnMajorAlternating180Layout OddRowOddColumnLayout;
};
// layout example of 4x4
// 00 07 08 15
// 01 06 09 14
// 02 05 10 13
// 03 04 11 12
//
class ColumnMajorAlternatingLayout : public ColumnMajorAlternatingTilePreference
{
public:
static uint16_t Map(uint16_t width, uint16_t height, uint16_t x, uint16_t y)
{
uint16_t index = x * height;
if (x & 0x0001)
{
index += ((height - 1) - y);
}
else
{
index += y;
}
return index;
}
};
// layout example of 4x4
// 03 02 01 00
// 04 05 06 07
// 11 10 09 08
// 12 13 14 15
//
class ColumnMajorAlternating90Layout : public ColumnMajorAlternatingTilePreference
{
public:
static uint16_t Map(uint16_t width, uint16_t height, uint16_t x, uint16_t y)
{
uint16_t index = y * width;
if (y & 0x0001)
{
index += x;
}
else
{
index += ((width - 1) - x);
}
return index;
}
};
// layout example of 4x4
// 12 11 04 03
// 13 10 05 02
// 14 09 06 01
// 15 08 07 00
//
class ColumnMajorAlternating180Layout : public ColumnMajorAlternatingTilePreference
{
public:
static uint16_t Map(uint16_t width, uint16_t height, uint16_t x, uint16_t y)
{
uint16_t mx = ((width - 1) - x);
uint16_t index = mx * height;
if (mx & 0x0001)
{
index += y;
}
else
{
index += ((height - 1) - y);
}
return index;
}
};
// layout example of 4x4
// 15 14 13 12
// 08 09 10 11
// 07 06 05 04
// 00 01 02 03
//
class ColumnMajorAlternating270Layout : public ColumnMajorAlternatingTilePreference
{
public:
static uint16_t Map(uint16_t width, uint16_t height, uint16_t x, uint16_t y)
{
uint16_t my = ((height - 1) - y);
uint16_t index = my * width;
if (my & 0x0001)
{
index += ((width - 1) - x);
}
else
{
index += x;
}
return index;
}
};

View File

@@ -30,26 +30,23 @@ class Neo3Elements
{
public:
static const size_t PixelSize = 3;
static const RgbColor Empty();
static uint8_t* getPixelAddress(uint8_t* pPixels, uint16_t indexPixel)
{
return &pPixels[indexPixel * PixelSize];
return pPixels + indexPixel * PixelSize;
}
typedef RgbColor ColorObject;
};
class Neo4Elements
{
public:
static const size_t PixelSize = 4;
static const RgbColor Empty();
static uint8_t* getPixelAddress(uint8_t* pPixels, uint16_t indexPixel)
{
return &pPixels[indexPixel * PixelSize];
return pPixels + indexPixel * PixelSize;
}
typedef RgbwColor ColorObject;

View File

@@ -28,187 +28,197 @@ License along with NeoPixel. If not, see
#ifdef ARDUINO_ARCH_AVR
typedef float(*AnimEaseFunction)(float linear);
typedef float(*AnimEaseFunction)(float unitValue);
#else
#undef max
#undef min
#include <functional>
typedef std::function<float(float linear)> AnimEaseFunction;
typedef std::function<float(float unitValue)> AnimEaseFunction;
#endif
class NeoEase
{
public:
static float QuadraticIn(float linear)
static float Linear(float unitValue)
{
return linear * linear;
return unitValue;
}
static float QuadraticOut(float linear)
static float QuadraticIn(float unitValue)
{
return (-linear * (linear - 2.0f));
return unitValue * unitValue;
}
static float QuadraticInOut(float linear)
static float QuadraticOut(float unitValue)
{
linear *= 2.0f;
if (linear < 1.0f)
return (-unitValue * (unitValue - 2.0f));
}
static float QuadraticInOut(float unitValue)
{
unitValue *= 2.0f;
if (unitValue < 1.0f)
{
return (0.5f * linear * linear);
return (0.5f * unitValue * unitValue);
}
else
{
linear -= 1.0f;
return (-0.5f * (linear * (linear - 2.0f) - 1.0f));
unitValue -= 1.0f;
return (-0.5f * (unitValue * (unitValue - 2.0f) - 1.0f));
}
}
static float CubicIn(float linear)
static float CubicIn(float unitValue)
{
return (linear * linear * linear);
return (unitValue * unitValue * unitValue);
}
static float CubicOut(float linear)
static float CubicOut(float unitValue)
{
linear -= 1.0f;
return (linear * linear * linear + 1);
unitValue -= 1.0f;
return (unitValue * unitValue * unitValue + 1);
}
static float CubicInOut(float linear)
static float CubicInOut(float unitValue)
{
linear *= 2.0f;
if (linear < 1.0f)
unitValue *= 2.0f;
if (unitValue < 1.0f)
{
return (0.5f * linear * linear * linear);
return (0.5f * unitValue * unitValue * unitValue);
}
else
{
linear -= 2.0f;
return (0.5f * (linear * linear * linear + 2.0f));
unitValue -= 2.0f;
return (0.5f * (unitValue * unitValue * unitValue + 2.0f));
}
}
static float QuarticIn(float linear)
static float QuarticIn(float unitValue)
{
return (linear * linear * linear * linear);
return (unitValue * unitValue * unitValue * unitValue);
}
static float QuarticOut(float linear)
static float QuarticOut(float unitValue)
{
linear -= 1.0f;
return -(linear * linear * linear * linear - 1);
unitValue -= 1.0f;
return -(unitValue * unitValue * unitValue * unitValue - 1);
}
static float QuarticInOut(float linear)
static float QuarticInOut(float unitValue)
{
linear *= 2.0f;
if (linear < 1.0f)
unitValue *= 2.0f;
if (unitValue < 1.0f)
{
return (0.5f * linear * linear * linear * linear);
return (0.5f * unitValue * unitValue * unitValue * unitValue);
}
else
{
linear -= 2.0f;
return (-0.5f * (linear * linear * linear * linear - 2.0f));
unitValue -= 2.0f;
return (-0.5f * (unitValue * unitValue * unitValue * unitValue - 2.0f));
}
}
static float QuinticIn(float linear)
static float QuinticIn(float unitValue)
{
return (linear * linear * linear * linear * linear);
return (unitValue * unitValue * unitValue * unitValue * unitValue);
}
static float QuinticOut(float linear)
static float QuinticOut(float unitValue)
{
linear -= 1.0f;
return (linear * linear * linear * linear * linear + 1.0f);
unitValue -= 1.0f;
return (unitValue * unitValue * unitValue * unitValue * unitValue + 1.0f);
}
static float QuinticInOut(float linear)
static float QuinticInOut(float unitValue)
{
linear *= 2.0f;
if (linear < 1.0f)
unitValue *= 2.0f;
if (unitValue < 1.0f)
{
return (0.5f * linear * linear * linear * linear * linear);
return (0.5f * unitValue * unitValue * unitValue * unitValue * unitValue);
}
else
{
linear -= 2.0f;
return (0.5f * (linear * linear * linear * linear * linear + 2.0f));
unitValue -= 2.0f;
return (0.5f * (unitValue * unitValue * unitValue * unitValue * unitValue + 2.0f));
}
}
static float SinusoidalIn(float linear)
static float SinusoidalIn(float unitValue)
{
return (-cos(linear * HALF_PI) + 1.0f);
return (-cos(unitValue * HALF_PI) + 1.0f);
}
static float SinusoidalOut(float linear)
static float SinusoidalOut(float unitValue)
{
return (sin(linear * HALF_PI));
return (sin(unitValue * HALF_PI));
}
static float SinusoidalInOut(float linear)
static float SinusoidalInOut(float unitValue)
{
return -0.5 * (cos(PI * linear) - 1.0f);
return -0.5 * (cos(PI * unitValue) - 1.0f);
}
static float ExponentialIn(float linear)
static float ExponentialIn(float unitValue)
{
return (pow(2, 10.0f * (linear - 1.0f)));
return (pow(2, 10.0f * (unitValue - 1.0f)));
}
static float ExponentialOut(float linear)
static float ExponentialOut(float unitValue)
{
return (-pow(2, -10.0f * linear) + 1.0f);
return (-pow(2, -10.0f * unitValue) + 1.0f);
}
static float ExponentialInOut(float linear)
static float ExponentialInOut(float unitValue)
{
linear *= 2.0f;
if (linear < 1.0f)
unitValue *= 2.0f;
if (unitValue < 1.0f)
{
return (0.5f * pow(2, 10.0f * (linear - 1.0f)));
return (0.5f * pow(2, 10.0f * (unitValue - 1.0f)));
}
else
{
linear -= 1.0f;
return (0.5f * (-pow(2, -10.0f * linear) + 2.0f));
unitValue -= 1.0f;
return (0.5f * (-pow(2, -10.0f * unitValue) + 2.0f));
}
}
static float CircularIn(float linear)
static float CircularIn(float unitValue)
{
if (linear == 1.0f)
if (unitValue == 1.0f)
{
return 1.0f;
}
else
{
return (-(sqrt(1.0f - linear * linear) - 1.0f));
return (-(sqrt(1.0f - unitValue * unitValue) - 1.0f));
}
}
static float CircularOut(float linear)
static float CircularOut(float unitValue)
{
linear -= 1.0f;
return (sqrt(1.0f - linear * linear));
unitValue -= 1.0f;
return (sqrt(1.0f - unitValue * unitValue));
}
static float CircularInOut(float linear)
static float CircularInOut(float unitValue)
{
linear *= 2.0f;
if (linear < 1.0f)
unitValue *= 2.0f;
if (unitValue < 1.0f)
{
return (-0.5f * (sqrt(1.0f - linear * linear) - 1));
return (-0.5f * (sqrt(1.0f - unitValue * unitValue) - 1));
}
else
{
linear -= 2.0f;
return (0.5f * (sqrt(1.0f - linear * linear) + 1.0f));
unitValue -= 2.0f;
return (0.5f * (sqrt(1.0f - unitValue * unitValue) + 1.0f));
}
}
static float Gamma(float unitValue)
{
return pow(unitValue, 1.0f / 0.45f);
}
};

90
src/internal/NeoGamma.h Normal file
View File

@@ -0,0 +1,90 @@
/*-------------------------------------------------------------------------
NeoPixelGamma class is used to correct RGB colors for human eye gamma levels
Written by Michael C. Miller.
I invest time and resources providing this open source code,
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
-------------------------------------------------------------------------
This file is part of the Makuna/NeoPixelBus library.
NeoPixelBus is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
NeoPixelBus is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with NeoPixel. If not, see
<http://www.gnu.org/licenses/>.
-------------------------------------------------------------------------*/
#pragma once
// NeoGammaEquationMethod uses no memory but is slower than NeoGammaTableMethod
class NeoGammaEquationMethod
{
public:
static uint8_t Correct(uint8_t value)
{
return static_cast<uint8_t>(255.0f * NeoEase::Gamma(value / 255.0f) + 0.5f);
}
};
// NeoGammaTableMethod uses 256 bytes of memory, but is significantly faster
class NeoGammaTableMethod
{
public:
static uint8_t Correct(uint8_t value)
{
return _table[value];
}
private:
static const uint8_t _table[256];
};
// use one of the method classes above as a converter for this template class
template<typename T_METHOD> class NeoGamma
{
public:
RgbColor Correct(const RgbColor& original)
{
return RgbColor(T_METHOD::Correct(original.R),
T_METHOD::Correct(original.G),
T_METHOD::Correct(original.B));
}
RgbwColor Correct(const RgbwColor& original)
{
return RgbwColor(T_METHOD::Correct(original.R),
T_METHOD::Correct(original.G),
T_METHOD::Correct(original.B),
T_METHOD::Correct(original.W) );
}
};
const uint8_t NeoGammaTableMethod::_table[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2,
3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6,
6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 11, 11, 11,
12, 12, 13, 13, 14, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19,
19, 20, 20, 21, 22, 22, 23, 23, 24, 25, 25, 26, 26, 27, 28, 28,
29, 30, 30, 31, 32, 33, 33, 34, 35, 35, 36, 37, 38, 39, 39, 40,
41, 42, 43, 43, 44, 45, 46, 47, 48, 49, 50, 50, 51, 52, 53, 54,
55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 71,
72, 73, 74, 75, 76, 77, 78, 80, 81, 82, 83, 84, 86, 87, 88, 89,
91, 92, 93, 94, 96, 97, 98, 100, 101, 102, 104, 105, 106, 108, 109, 110,
112, 113, 115, 116, 118, 119, 121, 122, 123, 125, 126, 128, 130, 131, 133, 134,
136, 137, 139, 140, 142, 144, 145, 147, 149, 150, 152, 154, 155, 157, 159, 160,
162, 164, 166, 167, 169, 171, 173, 175, 176, 178, 180, 182, 184, 186, 187, 189,
191, 193, 195, 197, 199, 201, 203, 205, 207, 209, 211, 213, 215, 217, 219, 221,
223, 225, 227, 229, 231, 233, 235, 238, 240, 242, 244, 246, 248, 251, 253, 255
};

157
src/internal/NeoMosaic.h Normal file
View File

@@ -0,0 +1,157 @@
#pragma once
/*-------------------------------------------------------------------------
Mosiac provides a mapping feature of a 2d cordinate to linear 1d cordinate
It is used to map tiles of matricies of NeoPixels to a index on the NeoPixelBus
where the the matricies use a set of prefered topology and the tiles of
those matricies use the RowMajorAlternating layout
Written by Michael C. Miller.
I invest time and resources providing this open source code,
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
-------------------------------------------------------------------------
This file is part of the Makuna/NeoPixelBus library.
NeoPixelBus is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
NeoPixelBus is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with NeoPixel. If not, see
<http://www.gnu.org/licenses/>.
-------------------------------------------------------------------------*/
//-----------------------------------------------------------------------------
// class NeoMosaic
// Complex Tile layout class that reduces distance of the interconnects between
// the tiles by using different rotations of the layout at specific locations
//
// T_LAYOUT = the layout used for matrix panel (rotation is ignored)
//
// NOTE: The tiles in the mosaic are always laid out using RowMajorAlternating
//
//-----------------------------------------------------------------------------
template <typename T_LAYOUT> class NeoMosaic
{
public:
NeoMosaic(uint16_t topoWidth, uint16_t topoHeight,
uint16_t mosaicWidth, uint16_t mosaicHeight) :
_topoWidth(topoWidth),
_topoHeight(topoHeight),
_mosaicWidth(mosaicWidth),
_mosaicHeight(mosaicHeight)
{
}
uint16_t Map(uint16_t x, uint16_t y) const
{
uint16_t localIndex;
uint16_t tileOffset;
calculate(x, y, &localIndex, &tileOffset);
return localIndex + tileOffset;
}
NeoTopologyHint TopologyHint(uint16_t x, uint16_t y) const
{
uint16_t localIndex;
uint16_t tileOffset;
NeoTopologyHint result;
calculate(x, y, &localIndex, &tileOffset);
if (localIndex == 0)
{
result = NeoTopologyHint_FirstOnPanel;
}
else if (localIndex == (_topoWidth * _topoHeight - 1))
{
result = NeoTopologyHint_LastOnPanel;
}
else
{
result = NeoTopologyHint_InPanel;
}
return result;
}
uint16_t getWidth() const
{
return _topoWidth * _mosaicWidth;
}
uint16_t getHeight() const
{
return _topoHeight * _mosaicHeight;
}
private:
const uint16_t _topoWidth;
const uint16_t _topoHeight;
const uint16_t _mosaicWidth;
const uint16_t _mosaicHeight;
void calculate(uint16_t x, uint16_t y, uint16_t* pLocalIndex, uint16_t* pTileOffset) const
{
uint16_t totalWidth = getWidth();
uint16_t totalHeight = getHeight();
if (x >= totalWidth)
{
x = totalWidth - 1;
}
if (y >= totalHeight)
{
y = totalHeight - 1;
}
uint16_t tileX = x / _topoWidth;
uint16_t topoX = x % _topoWidth;
uint16_t tileY = y / _topoHeight;
uint16_t topoY = y % _topoHeight;
*pTileOffset = RowMajorAlternatingLayout::Map(_mosaicWidth,
_mosaicHeight,
tileX,
tileY) * _topoWidth * _topoHeight;
if (tileX & 0x0001)
{
// odd columns
if (tileY & 0x0001)
{
*pLocalIndex = T_LAYOUT::OddRowOddColumnLayout::Map(_topoWidth, _topoHeight, topoX, topoY);
}
else
{
*pLocalIndex = T_LAYOUT::EvenRowOddColumnLayout::Map(_topoWidth, _topoHeight, topoX, topoY);
}
}
else
{
// even columns
if (tileY & 0x0001)
{
*pLocalIndex = T_LAYOUT::OddRowEvenColumnLayout::Map(_topoWidth, _topoHeight, topoX, topoY);
}
else
{
*pLocalIndex = T_LAYOUT::EvenRowEvenColumnLayout::Map(_topoWidth, _topoHeight, topoX, topoY);
}
}
}
};

View File

@@ -32,10 +32,7 @@ NeoPixelAnimator::NeoPixelAnimator(uint16_t countAnimations, uint16_t timeScale)
_activeAnimations(0),
_isRunning(true)
{
// due to strange esp include header issues, min and max aren't usable
_timeScale = (timeScale < 1) ? (1) : (timeScale > 32768) ? 32768 : timeScale;
//_timeScale = max(1, min(32768, timeScale));
setTimeScale(timeScale);
_animations = new AnimationContext[_countAnimations];
}

124
src/internal/NeoTiles.h Normal file
View File

@@ -0,0 +1,124 @@
#pragma once
/*-------------------------------------------------------------------------
NeoTiles provides a mapping feature of a 2d cordinate to linear 1d cordinate
It is used to map tiles of matricies of NeoPixels to a index on the NeoPixelBus
where the the matricies use one topology and the tiles of those matricies can
use another
Written by Michael C. Miller.
I invest time and resources providing this open source code,
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
-------------------------------------------------------------------------
This file is part of the Makuna/NeoPixelBus library.
NeoPixelBus is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
NeoPixelBus is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with NeoPixel. If not, see
<http://www.gnu.org/licenses/>.
-------------------------------------------------------------------------*/
//-----------------------------------------------------------------------------
// class NeoTiles
// Simple template Tile layout class
// T_MATRIX_LAYOUT = the layout used on the pixel matrix panel (a tile)
// T_TILE_LAYOUT = the layout used for the tiles.
//
//-----------------------------------------------------------------------------
template <typename T_MATRIX_LAYOUT, typename T_TILE_LAYOUT> class NeoTiles
{
public:
NeoTiles(uint16_t topoWidth, uint16_t topoHeight,
uint16_t tilesWidth, uint16_t tilesHeight) :
_topo(topoWidth, topoHeight),
_width(tilesWidth),
_height(tilesHeight)
{
}
uint16_t Map(uint16_t x, uint16_t y) const
{
uint16_t localIndex;
uint16_t tileOffset;
calculate(x, y, &localIndex, &tileOffset);
return localIndex + tileOffset;
}
NeoTopologyHint TopologyHint(uint16_t x, uint16_t y) const
{
uint16_t localIndex;
uint16_t tileOffset;
NeoTopologyHint result;
calculate(x, y, &localIndex, &tileOffset);
if (localIndex == 0)
{
result = NeoTopologyHint_FirstOnPanel;
}
else if (localIndex == (_topo.getWidth() * _topo.getHeight() - 1))
{
result = NeoTopologyHint_LastOnPanel;
}
else
{
result = NeoTopologyHint_InPanel;
}
return result;
}
uint16_t getWidth() const
{
return _width * _topo.getWidth();
}
uint16_t getHeight() const
{
return _height * _topo.getHeight();
}
private:
const NeoTopology<T_MATRIX_LAYOUT> _topo;
const uint16_t _width;
const uint16_t _height;
void calculate(uint16_t x, uint16_t y, uint16_t* pLocalIndex, uint16_t* pTileOffset) const
{
uint16_t totalWidth = getWidth();
uint16_t totalHeight = getHeight();
if (x >= totalWidth)
{
x = totalWidth - 1;
}
if (y >= totalHeight)
{
y = totalHeight - 1;
}
uint16_t tileX = x / _topo.getWidth();
uint16_t topoX = x % _topo.getWidth();
uint16_t tileY = y / _topo.getHeight();
uint16_t topoY = y % _topo.getHeight();
*pTileOffset = T_TILE_LAYOUT::Map(_width, _height, tileX, tileY) * _topo.getWidth() * _topo.getHeight();
*pLocalIndex = _topo.Map(topoX, topoY);
}
};

View File

@@ -0,0 +1,73 @@
#pragma once
/*-------------------------------------------------------------------------
NeoTopology provides a mapping feature of a 2d cordinate to linear 1d cordinate
It is used to map a matrix of NeoPixels to a index on the NeoPixelBus
Written by Michael C. Miller.
I invest time and resources providing this open source code,
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
-------------------------------------------------------------------------
This file is part of the Makuna/NeoPixelBus library.
NeoPixelBus is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
NeoPixelBus is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with NeoPixel. If not, see
<http://www.gnu.org/licenses/>.
-------------------------------------------------------------------------*/
enum NeoTopologyHint
{
NeoTopologyHint_FirstOnPanel,
NeoTopologyHint_InPanel,
NeoTopologyHint_LastOnPanel,
};
template <typename T_LAYOUT> class NeoTopology
{
public:
NeoTopology(uint16_t width, uint16_t height) :
_width(width),
_height(height)
{
}
uint16_t Map(uint16_t x, uint16_t y) const
{
if (x >= _width)
{
x = _width - 1;
}
if (y >= _height)
{
y = _height - 1;
}
return T_LAYOUT::Map(_width, _height, x, y);
}
uint16_t getWidth() const
{
return _width;
}
uint16_t getHeight() const
{
return _height;
}
private:
const uint16_t _width;
const uint16_t _height;
};

View File

@@ -217,9 +217,27 @@ void RgbColor::Lighten(uint8_t delta)
}
}
RgbColor RgbColor::LinearBlend(RgbColor left, RgbColor right, float progress)
RgbColor RgbColor::LinearBlend(const RgbColor& left, const RgbColor& right, float progress)
{
return RgbColor( left.R + ((right.R - left.R) * progress),
left.G + ((right.G - left.G) * progress),
left.B + ((right.B - left.B) * progress));
}
RgbColor RgbColor::BilinearBlend(const RgbColor& c00,
const RgbColor& c01,
const RgbColor& c10,
const RgbColor& c11,
float x,
float y)
{
float v00 = (1.0f - x) * (1.0f - y);
float v10 = x * (1.0f - y);
float v01 = (1.0f - x) * y;
float v11 = x * y;
return RgbColor(
c00.R * v00 + c10.R * v10 + c01.R * v01 + c11.R * v11,
c00.G * v00 + c10.G * v10 + c01.G * v01 + c11.G * v11,
c00.B * v00 + c10.B * v10 + c01.B * v01 + c11.B * v11);
}

View File

@@ -79,6 +79,16 @@ struct RgbColor
{
};
bool operator==(const RgbColor& other) const
{
return (R == other.R && G == other.G && B == other.B);
};
bool operator!=(const RgbColor& other) const
{
return !(*this == other);
};
// ------------------------------------------------------------------------
// CalculateBrightness will calculate the overall brightness
// NOTE: This is a simple linear brightness
@@ -93,7 +103,7 @@ struct RgbColor
void Darken(uint8_t delta);
// ------------------------------------------------------------------------
// Lighten will adjust the color by the given delta toward white
// Lighten will adjust the color by the given delta toward ite
// NOTE: This is a simple linear change
// delta - (0-255) the amount to lighten the color
// ------------------------------------------------------------------------
@@ -106,7 +116,23 @@ struct RgbColor
// progress - (0.0 - 1.0) value where 0 will return left and 1.0 will return right
// and a value between will blend the color weighted linearly between them
// ------------------------------------------------------------------------
static RgbColor LinearBlend(RgbColor left, RgbColor right, float progress);
static RgbColor LinearBlend(const RgbColor& left, const RgbColor& right, float progress);
// ------------------------------------------------------------------------
// BilinearBlend between four colors by the amount defined by 2d variable
// c00 - upper left quadrant color
// c01 - upper right quadrant color
// c10 - lower left quadrant color
// c11 - lower right quadrant color
// x - unit value (0.0 - 1.0) that defines the blend progress in horizontal space
// y - unit value (0.0 - 1.0) that defines the blend progress in vertical space
// ------------------------------------------------------------------------
static RgbColor BilinearBlend(const RgbColor& c00,
const RgbColor& c01,
const RgbColor& c10,
const RgbColor& c11,
float x,
float y);
// ------------------------------------------------------------------------
// Red, Green, Blue color members (0-255) where

View File

@@ -29,13 +29,13 @@ License along with NeoPixel. If not, see
#include "HsbColor.h"
#include "RgbwColor.h"
RgbwColor::RgbwColor(HslColor color)
RgbwColor::RgbwColor(const HslColor& color)
{
RgbColor rgbColor(color);
*this = rgbColor;
}
RgbwColor::RgbwColor(HsbColor color)
RgbwColor::RgbwColor(const HsbColor& color)
{
RgbColor rgbColor(color);
*this = rgbColor;
@@ -137,10 +137,29 @@ void RgbwColor::Lighten(uint8_t delta)
}
}
RgbwColor RgbwColor::LinearBlend(RgbwColor left, RgbwColor right, float progress)
RgbwColor RgbwColor::LinearBlend(const RgbwColor& left, const RgbwColor& right, float progress)
{
return RgbwColor( left.R + ((right.R - left.R) * progress),
left.G + ((right.G - left.G) * progress),
left.B + ((right.B - left.B) * progress),
left.W + ((right.W - left.W) * progress) );
}
RgbwColor RgbwColor::BilinearBlend(const RgbwColor& c00,
const RgbwColor& c01,
const RgbwColor& c10,
const RgbwColor& c11,
float x,
float y)
{
float v00 = (1.0f - x) * (1.0f - y);
float v10 = x * (1.0f - y);
float v01 = (1.0f - x) * y;
float v11 = x * y;
return RgbwColor(
c00.R * v00 + c10.R * v10 + c01.R * v01 + c11.R * v11,
c00.G * v00 + c10.G * v10 + c01.G * v01 + c11.G * v11,
c00.B * v00 + c10.B * v10 + c01.B * v01 + c11.B * v11,
c00.W * v00 + c10.W * v10 + c01.W * v01 + c11.W * v11 );
}

View File

@@ -59,7 +59,7 @@ struct RgbwColor
// ------------------------------------------------------------------------
// Construct a RgbwColor using RgbColor
// ------------------------------------------------------------------------
RgbwColor(RgbColor color) :
RgbwColor(const RgbColor& color) :
R(color.R),
G(color.G),
B(color.B),
@@ -71,12 +71,12 @@ struct RgbwColor
// ------------------------------------------------------------------------
// Construct a RgbwColor using HslColor
// ------------------------------------------------------------------------
RgbwColor(HslColor color);
RgbwColor(const HslColor& color);
// ------------------------------------------------------------------------
// Construct a RgbwColor using HsbColor
// ------------------------------------------------------------------------
RgbwColor(HsbColor color);
RgbwColor(const HsbColor& color);
// ------------------------------------------------------------------------
// Construct a RgbwColor that will have its values set in latter operations
@@ -86,6 +86,16 @@ struct RgbwColor
{
};
bool operator==(const RgbwColor& other) const
{
return (R == other.R && G == other.G && B == other.B && W == other.W);
};
bool operator!=(const RgbwColor& other) const
{
return !(*this == other);
};
// ------------------------------------------------------------------------
// Returns if the color is grey, all values are equal other than white
// ------------------------------------------------------------------------
@@ -130,7 +140,23 @@ struct RgbwColor
// progress - (0.0 - 1.0) value where 0 will return left and 1.0 will return right
// and a value between will blend the color weighted linearly between them
// ------------------------------------------------------------------------
static RgbwColor LinearBlend(RgbwColor left, RgbwColor right, float progress);
static RgbwColor LinearBlend(const RgbwColor& left, const RgbwColor& right, float progress);
// ------------------------------------------------------------------------
// BilinearBlend between four colors by the amount defined by 2d variable
// c00 - upper left quadrant color
// c01 - upper right quadrant color
// c10 - lower left quadrant color
// c11 - lower right quadrant color
// x - unit value (0.0 - 1.0) that defines the blend progress in horizontal space
// y - unit value (0.0 - 1.0) that defines the blend progress in vertical space
// ------------------------------------------------------------------------
static RgbwColor BilinearBlend(const RgbwColor& c00,
const RgbwColor& c01,
const RgbwColor& c10,
const RgbwColor& c11,
float x,
float y);
// ------------------------------------------------------------------------
// Red, Green, Blue, White color members (0-255) where