Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/FastLED/FastLED.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Garcia <danielgarcia@gmail.com>2016-01-23 22:15:34 +0300
committerDaniel Garcia <danielgarcia@gmail.com>2016-01-23 22:15:34 +0300
commit45b804fe04c3e02ba85d5eb63e9daf4d83dd432b (patch)
tree3b145fd5a0291a45855b3f35174f79c555680916
parent92928ce02cba8183209bbfcf022f4622b6cd84d6 (diff)
parent6d6aca7330c4c2e1b29cf791dbf2550692da59d2 (diff)
Merge branch 'master' into rgbw
-rw-r--r--FastLED.cpp6
-rw-r--r--FastLED.h7
-rw-r--r--README.md3
-rw-r--r--bitswap.h2
-rw-r--r--chipsets.h14
-rw-r--r--color.h2
-rw-r--r--colorpalettes.h1
-rw-r--r--colorutils.cpp402
-rw-r--r--colorutils.h473
-rw-r--r--controller.h1
-rw-r--r--cpp_compat.h2
-rw-r--r--dmx.h1
-rw-r--r--docs/.Doxyfile.swpbin126976 -> 0 bytes
-rw-r--r--examples/DemoReel100/DemoReel100.ino2
-rw-r--r--examples/RGBSetDemo/RGBSetDemo.ino22
-rw-r--r--examples/XYMatrix/XYMatrix.ino5
-rw-r--r--fastled_config.h10
-rw-r--r--fastled_delay.h11
-rw-r--r--fastled_progmem.h2
-rw-r--r--fastpin.h6
-rw-r--r--fastspi.h2
-rw-r--r--fastspi_bitbang.h48
-rw-r--r--fastspi_nop.h5
-rw-r--r--fastspi_ref.h6
-rw-r--r--fastspi_types.h2
-rw-r--r--hsv2rgb.cpp191
-rw-r--r--hsv2rgb.h2
-rw-r--r--led_sysdefs.h2
-rw-r--r--lib8tion.h16
-rw-r--r--lib8tion/math8.h53
-rw-r--r--lib8tion/scale8.h18
-rw-r--r--library.properties2
-rw-r--r--noise.cpp57
-rw-r--r--noise.h4
-rw-r--r--pixelset.h300
-rw-r--r--pixeltypes.h2
-rw-r--r--platforms.h2
-rw-r--r--platforms/avr/fastpin_avr.h60
-rw-r--r--power_mgt.h2
-rw-r--r--release_notes.md11
40 files changed, 1590 insertions, 167 deletions
diff --git a/FastLED.cpp b/FastLED.cpp
index af92429e..949372ea 100644
--- a/FastLED.cpp
+++ b/FastLED.cpp
@@ -114,14 +114,18 @@ void CFastLED::clearData() {
void CFastLED::delay(unsigned long ms) {
unsigned long start = millis();
- while((millis()-start) < ms) {
+ do {
#ifndef FASTLED_ACCURATE_CLOCK
// make sure to allow at least one ms to pass to ensure the clock moves
// forward
::delay(1);
#endif
show();
+#if defined(ARDUINO) && (ARDUINO > 150)
+ yield();
+#endif
}
+ while((millis()-start) < ms);
}
void CFastLED::setTemperature(const struct CRGB & temp) {
diff --git a/FastLED.h b/FastLED.h
index b515e124..496411a1 100644
--- a/FastLED.h
+++ b/FastLED.h
@@ -45,8 +45,10 @@
#include "fastled_progmem.h"
#include "lib8tion.h"
+#include "pixeltypes.h"
#include "hsv2rgb.h"
#include "colorutils.h"
+#include "pixelset.h"
#include "colorpalettes.h"
#include "noise.h"
@@ -85,9 +87,11 @@ template<uint8_t DATA_PIN, EOrder RGB_ORDER> class TM1803 : public TM1803Control
template<uint8_t DATA_PIN, EOrder RGB_ORDER> class UCS1903 : public UCS1903Controller400Khz<DATA_PIN, RGB_ORDER> {};
template<uint8_t DATA_PIN, EOrder RGB_ORDER> class UCS1903B : public UCS1903BController800Khz<DATA_PIN, RGB_ORDER> {};
template<uint8_t DATA_PIN, EOrder RGB_ORDER> class UCS1904 : public UCS1904Controller800Khz<DATA_PIN, RGB_ORDER> {};
+template<uint8_t DATA_PIN, EOrder RGB_ORDER> class UCS2903 : public UCS2903Controller<DATA_PIN, RGB_ORDER> {};
template<uint8_t DATA_PIN, EOrder RGB_ORDER> class WS2812 : public WS2812Controller800Khz<DATA_PIN, RGB_ORDER> {};
template<uint8_t DATA_PIN, EOrder RGB_ORDER> class WS2812B : public WS2812Controller800Khz<DATA_PIN, RGB_ORDER> {};
template<uint8_t DATA_PIN, EOrder RGB_ORDER> class SK6812 : public SK6812Controller<DATA_PIN, RGB_ORDER> {};
+template<uint8_t DATA_PIN, EOrder RGB_ORDER> class SK6822 : public SK6822Controller<DATA_PIN, RGB_ORDER> {};
template<uint8_t DATA_PIN, EOrder RGB_ORDER> class PL9823 : public PL9823Controller<DATA_PIN, RGB_ORDER> {};
template<uint8_t DATA_PIN, EOrder RGB_ORDER> class WS2811 : public WS2811Controller800Khz<DATA_PIN, RGB_ORDER> {};
template<uint8_t DATA_PIN, EOrder RGB_ORDER> class APA104 : public WS2811Controller800Khz<DATA_PIN, RGB_ORDER> {};
@@ -438,7 +442,8 @@ public:
void showColor(const struct CRGB & color) { showColor(color, m_Scale); }
/// Delay for the given number of milliseconds. Provided to allow the library to be used on platforms
- /// that don't have a delay function (to allow code to be more portable)
+ /// that don't have a delay function (to allow code to be more portable). Note: this will call show
+ /// constantly to drive the dithering engine (and will call show at least once).
/// @param ms the number of milliseconds to pause for
void delay(unsigned long ms);
diff --git a/README.md b/README.md
index 0f1e3bbf..d70499a3 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,7 @@
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/FastLED/public)
-IMPORTANT NOTE: For AVR based systems, avr-gcc 4.8.x is supported, as is avr-gcc 4.3 and earlier. There are known issues with avr-gcc 4.7 and timing based chipsets like the WS2812B. If you are using a linux system make sure you are using avr-gcc 4.8.x not avr-gcc 4.7.x.
+IMPORTANT NOTE: For AVR based systems, avr-gcc 4.8.x is supported and tested. This means Arduino 1.6.5 and later.
+
FastLED 3.1
===========
diff --git a/bitswap.h b/bitswap.h
index 3af7d1b2..5e72daed 100644
--- a/bitswap.h
+++ b/bitswap.h
@@ -1,6 +1,8 @@
#ifndef __INC_BITSWAP_H
#define __INC_BITSWAP_H
+#include "FastLED.h"
+
FASTLED_NAMESPACE_BEGIN
///@file bitswap.h
diff --git a/chipsets.h b/chipsets.h
index ade34d97..d2b6a809 100644
--- a/chipsets.h
+++ b/chipsets.h
@@ -1,6 +1,7 @@
#ifndef __INC_CHIPSETS_H
#define __INC_CHIPSETS_H
+#include "FastLED.h"
#include "pixeltypes.h"
///@file chipsets.h
@@ -333,6 +334,9 @@ template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
class WS2811Controller400Khz : public ClocklessController<DATA_PIN, 4 * FMUL, 10 * FMUL, 6 * FMUL, RGB_ORDER> {};
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
+class SK6822Controller : public ClocklessController<DATA_PIN, 3 * FMUL, 8 * FMUL, 3 * FMUL, RGB_ORDER> {};
+
+template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
class SK6812Controller : public ClocklessController<DATA_PIN, 3 * FMUL, 3 * FMUL, 4 * FMUL, RGB_ORDER> {};
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
@@ -345,6 +349,9 @@ template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
class UCS1904Controller800Khz : public ClocklessController<DATA_PIN, 3 * FMUL, 3 * FMUL, 4 * FMUL, RGB_ORDER> {};
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
+class UCS2903Controller : public ClocklessController<DATA_PIN, 2 * FMUL, 6 * FMUL, 2 * FMUL, RGB_ORDER> {};
+
+template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
class TM1809Controller800Khz : public ClocklessController<DATA_PIN, 2 * FMUL, 5 * FMUL, 3 * FMUL, RGB_ORDER> {};
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
@@ -383,6 +390,10 @@ class UCS1903BController800Khz : public ClocklessController<DATA_PIN, NS(400), N
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
class UCS1904Controller800Khz : public ClocklessController<DATA_PIN, NS(400), NS(400), NS(450), RGB_ORDER> {};
+// UCS2903 - 250ns, 750ns, 250ns
+template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
+class UCS2903Controller : public ClocklessController<DATA_PIN, NS(250), NS(750), NS(250), RGB_ORDER> {};
+
// TM1809 - 350ns, 350ns, 550ns
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
class TM1809Controller800Khz : public ClocklessController<DATA_PIN, NS(350), NS(350), NS(450), RGB_ORDER> {};
@@ -413,6 +424,9 @@ template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
class LPD1886Controller1250Khz : public ClocklessController<DATA_PIN, NS(200), NS(400), NS(200), RGB_ORDER, 4> {};
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
+class SK6822Controller : public ClocklessController<DATA_PIN, NS(375), NS(1000), NS(375), RGB_ORDER> {};
+
+template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
class SK6812Controller : public ClocklessController<DATA_PIN, NS(300), NS(300), NS(600), RGB_ORDER> {};
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
diff --git a/color.h b/color.h
index 11b52d36..1ed60b4d 100644
--- a/color.h
+++ b/color.h
@@ -1,6 +1,8 @@
#ifndef __INC_COLOR_H
#define __INC_COLOR_H
+#include "FastLED.h"
+
FASTLED_NAMESPACE_BEGIN
///@file color.h
diff --git a/colorpalettes.h b/colorpalettes.h
index 97f0cb5d..4458575e 100644
--- a/colorpalettes.h
+++ b/colorpalettes.h
@@ -1,6 +1,7 @@
#ifndef __INC_COLORPALETTES_H
#define __INC_COLORPALETTES_H
+#include "FastLED.h"
#include "colorutils.h"
///@file colorpalettes.h
diff --git a/colorutils.cpp b/colorutils.cpp
index 5608cf85..80c694af 100644
--- a/colorutils.cpp
+++ b/colorutils.cpp
@@ -475,70 +475,103 @@ CRGB HeatColor( uint8_t temperature)
}
+// lsrX4: helper function to divide a number by 16, aka four LSR's.
+// On avr-gcc, "u8 >> 4" generates a loop, which is big, and slow.
+// merely forcing it to be four /=2's causes avr-gcc to emit
+// a SWAP instruction followed by an AND 0x0F, which is faster, and smaller.
+inline uint8_t lsrX4( uint8_t dividend) __attribute__((always_inline));
+inline uint8_t lsrX4( uint8_t dividend)
+{
+#if defined(__AVR__)
+ dividend /= 2;
+ dividend /= 2;
+ dividend /= 2;
+ dividend /= 2;
+#else
+ dividend >>= 4;
+#endif
+ return dividend;
+}
+
CRGB ColorFromPalette( const CRGBPalette16& pal, uint8_t index, uint8_t brightness, TBlendType blendType)
{
- uint8_t hi4 = index >> 4;
+ // hi4 = index >> 4;
+ uint8_t hi4 = lsrX4(index);
uint8_t lo4 = index & 0x0F;
-
- // CRGB rgb1 = pal[ hi4];
- const CRGB* entry = &(pal[0]) + hi4;
+
+ // const CRGB* entry = &(pal[0]) + hi4;
+ // since hi4 is always 0..15, hi4 * sizeof(CRGB) can be a single-byte value,
+ // instead of the two byte 'int' that avr-gcc defaults to.
+ // So, we multiply hi4 X sizeof(CRGB), giving hi4XsizeofCRGB;
+ uint8_t hi4XsizeofCRGB = hi4 * sizeof(CRGB);
+ // We then add that to a base array pointer.
+ const CRGB* entry = (CRGB*)( (uint8_t*)(&(pal[0])) + hi4XsizeofCRGB);
+
+ uint8_t blend = lo4 && (blendType != NOBLEND);
+
uint8_t red1 = entry->red;
uint8_t green1 = entry->green;
uint8_t blue1 = entry->blue;
-
- uint8_t blend = lo4 && (blendType != NOBLEND);
-
+
+
if( blend ) {
-
+
if( hi4 == 15 ) {
entry = &(pal[0]);
} else {
entry++;
}
-
+
uint8_t f2 = lo4 << 4;
uint8_t f1 = 255 - f2;
-
+
// rgb1.nscale8(f1);
+ uint8_t red2 = entry->red;
red1 = scale8_LEAVING_R1_DIRTY( red1, f1);
- green1 = scale8_LEAVING_R1_DIRTY( green1, f1);
- blue1 = scale8_LEAVING_R1_DIRTY( blue1, f1);
-
- // cleanup_R1();
+ red2 = scale8_LEAVING_R1_DIRTY( red2, f2);
+ red1 += red2;
- // CRGB rgb2 = pal[ hi4];
- // rgb2.nscale8(f2);
- uint8_t red2 = entry->red;
uint8_t green2 = entry->green;
- uint8_t blue2 = entry->blue;
- red2 = scale8_LEAVING_R1_DIRTY( red2, f2);
+ green1 = scale8_LEAVING_R1_DIRTY( green1, f1);
green2 = scale8_LEAVING_R1_DIRTY( green2, f2);
- blue2 = scale8_LEAVING_R1_DIRTY( blue2, f2);
-
- cleanup_R1();
-
- // These sums can't overflow, so no qadd8 needed.
- red1 += red2;
green1 += green2;
- blue1 += blue2;
+ uint8_t blue2 = entry->blue;
+ blue1 = scale8_LEAVING_R1_DIRTY( blue1, f1);
+ blue2 = scale8_LEAVING_R1_DIRTY( blue2, f2);
+ blue1 += blue2;
+
+ cleanup_R1();
}
-
+
if( brightness != 255) {
- nscale8x3_video( red1, green1, blue1, brightness);
+ if( brightness ) {
+ brightness++; // adjust for rounding
+ // Now, since brightness is nonzero, we don't need the full scale8_video logic;
+ // we can just to scale8 and then add one to all nonzero inputs.
+ if( red1 ) { red1 = scale8_LEAVING_R1_DIRTY( red1, brightness); red1++; }
+ if( green1 ) { green1 = scale8_LEAVING_R1_DIRTY( green1, brightness); green1++; }
+ if( blue1 ) { blue1 = scale8_LEAVING_R1_DIRTY( blue1, brightness); blue1++; }
+ cleanup_R1();
+ } else {
+ red1 = 0;
+ green1 = 0;
+ blue1 = 0;
+ }
}
-
+
return CRGB( red1, green1, blue1);
}
CRGB ColorFromPalette( const TProgmemRGBPalette16& pal, uint8_t index, uint8_t brightness, TBlendType blendType)
{
- uint8_t hi4 = index >> 4;
+ // hi4 = index >> 4;
+ uint8_t hi4 = lsrX4(index);
uint8_t lo4 = index & 0x0F;
- // CRGB rgb1 = pal[ hi4];
CRGB entry = FL_PGM_READ_DWORD_NEAR( &(pal[0]) + hi4 );
+
uint8_t red1 = entry.red;
uint8_t green1 = entry.green;
@@ -557,35 +590,185 @@ CRGB ColorFromPalette( const TProgmemRGBPalette16& pal, uint8_t index, uint8_t b
uint8_t f2 = lo4 << 4;
uint8_t f1 = 255 - f2;
- // rgb1.nscale8(f1);
+ uint8_t red2 = entry.red;
red1 = scale8_LEAVING_R1_DIRTY( red1, f1);
+ red2 = scale8_LEAVING_R1_DIRTY( red2, f2);
+ red1 += red2;
+
+ uint8_t green2 = entry.green;
green1 = scale8_LEAVING_R1_DIRTY( green1, f1);
+ green2 = scale8_LEAVING_R1_DIRTY( green2, f2);
+ green1 += green2;
+
+ uint8_t blue2 = entry.blue;
blue1 = scale8_LEAVING_R1_DIRTY( blue1, f1);
+ blue2 = scale8_LEAVING_R1_DIRTY( blue2, f2);
+ blue1 += blue2;
- // cleanup_R1();
+ cleanup_R1();
+ }
- // CRGB rgb2 = pal[ hi4];
- // rgb2.nscale8(f2);
- uint8_t red2 = entry.red;
- uint8_t green2 = entry.green;
- uint8_t blue2 = entry.blue;
+ if( brightness != 255) {
+ if( brightness ) {
+ brightness++; // adjust for rounding
+ // Now, since brightness is nonzero, we don't need the full scale8_video logic;
+ // we can just to scale8 and then add one to all nonzero inputs.
+ if( red1 ) { red1 = scale8_LEAVING_R1_DIRTY( red1, brightness); red1++; }
+ if( green1 ) { green1 = scale8_LEAVING_R1_DIRTY( green1, brightness); green1++; }
+ if( blue1 ) { blue1 = scale8_LEAVING_R1_DIRTY( blue1, brightness); blue1++; }
+ cleanup_R1();
+ } else {
+ red1 = 0;
+ green1 = 0;
+ blue1 = 0;
+ }
+ }
+
+ return CRGB( red1, green1, blue1);
+}
+
+
+CRGB ColorFromPalette( const CRGBPalette32& pal, uint8_t index, uint8_t brightness, TBlendType blendType)
+{
+ uint8_t hi5 = index;
+#if defined(__AVR__)
+ hi5 /= 2;
+ hi5 /= 2;
+ hi5 /= 2;
+#else
+ hi5 >>= 3;
+#endif
+ uint8_t lo3 = index & 0x07;
+
+ // const CRGB* entry = &(pal[0]) + hi5;
+ // since hi5 is always 0..31, hi4 * sizeof(CRGB) can be a single-byte value,
+ // instead of the two byte 'int' that avr-gcc defaults to.
+ // So, we multiply hi5 X sizeof(CRGB), giving hi5XsizeofCRGB;
+ uint8_t hi5XsizeofCRGB = hi5 * sizeof(CRGB);
+ // We then add that to a base array pointer.
+ const CRGB* entry = (CRGB*)( (uint8_t*)(&(pal[0])) + hi5XsizeofCRGB);
+
+ uint8_t red1 = entry->red;
+ uint8_t green1 = entry->green;
+ uint8_t blue1 = entry->blue;
+
+ uint8_t blend = lo3 && (blendType != NOBLEND);
+
+ if( blend ) {
+
+ if( hi5 == 31 ) {
+ entry = &(pal[0]);
+ } else {
+ entry++;
+ }
+
+ uint8_t f2 = lo3 << 5;
+ uint8_t f1 = 255 - f2;
+
+ uint8_t red2 = entry->red;
+ red1 = scale8_LEAVING_R1_DIRTY( red1, f1);
red2 = scale8_LEAVING_R1_DIRTY( red2, f2);
+ red1 += red2;
+
+ uint8_t green2 = entry->green;
+ green1 = scale8_LEAVING_R1_DIRTY( green1, f1);
green2 = scale8_LEAVING_R1_DIRTY( green2, f2);
+ green1 += green2;
+
+ uint8_t blue2 = entry->blue;
+ blue1 = scale8_LEAVING_R1_DIRTY( blue1, f1);
blue2 = scale8_LEAVING_R1_DIRTY( blue2, f2);
+ blue1 += blue2;
cleanup_R1();
+
+ }
+
+ if( brightness != 255) {
+ if( brightness ) {
+ brightness++; // adjust for rounding
+ // Now, since brightness is nonzero, we don't need the full scale8_video logic;
+ // we can just to scale8 and then add one to all nonzero inputs.
+ if( red1 ) { red1 = scale8_LEAVING_R1_DIRTY( red1, brightness); red1++; }
+ if( green1 ) { green1 = scale8_LEAVING_R1_DIRTY( green1, brightness); green1++; }
+ if( blue1 ) { blue1 = scale8_LEAVING_R1_DIRTY( blue1, brightness); blue1++; }
+ cleanup_R1();
+ } else {
+ red1 = 0;
+ green1 = 0;
+ blue1 = 0;
+ }
+ }
+
+ return CRGB( red1, green1, blue1);
+}
- // These sums can't overflow, so no qadd8 needed.
+
+CRGB ColorFromPalette( const TProgmemRGBPalette32& pal, uint8_t index, uint8_t brightness, TBlendType blendType)
+{
+ uint8_t hi5 = index;
+#if defined(__AVR__)
+ hi5 /= 2;
+ hi5 /= 2;
+ hi5 /= 2;
+#else
+ hi5 >>= 3;
+#endif
+ uint8_t lo3 = index & 0x07;
+
+ CRGB entry = FL_PGM_READ_DWORD_NEAR( &(pal[0]) + hi5);
+
+ uint8_t red1 = entry.red;
+ uint8_t green1 = entry.green;
+ uint8_t blue1 = entry.blue;
+
+ uint8_t blend = lo3 && (blendType != NOBLEND);
+
+ if( blend ) {
+
+ if( hi5 == 31 ) {
+ entry = FL_PGM_READ_DWORD_NEAR( &(pal[0]) );
+ } else {
+ entry = FL_PGM_READ_DWORD_NEAR( &(pal[1]) + hi5 );
+ }
+
+ uint8_t f2 = lo3 << 5;
+ uint8_t f1 = 255 - f2;
+
+ uint8_t red2 = entry.red;
+ red1 = scale8_LEAVING_R1_DIRTY( red1, f1);
+ red2 = scale8_LEAVING_R1_DIRTY( red2, f2);
red1 += red2;
+
+ uint8_t green2 = entry.green;
+ green1 = scale8_LEAVING_R1_DIRTY( green1, f1);
+ green2 = scale8_LEAVING_R1_DIRTY( green2, f2);
green1 += green2;
+
+ uint8_t blue2 = entry.blue;
+ blue1 = scale8_LEAVING_R1_DIRTY( blue1, f1);
+ blue2 = scale8_LEAVING_R1_DIRTY( blue2, f2);
blue1 += blue2;
-
+
+ cleanup_R1();
}
-
+
if( brightness != 255) {
- nscale8x3_video( red1, green1, blue1, brightness);
+ if( brightness ) {
+ brightness++; // adjust for rounding
+ // Now, since brightness is nonzero, we don't need the full scale8_video logic;
+ // we can just to scale8 and then add one to all nonzero inputs.
+ if( red1 ) { red1 = scale8_LEAVING_R1_DIRTY( red1, brightness); red1++; }
+ if( green1 ) { green1 = scale8_LEAVING_R1_DIRTY( green1, brightness); green1++; }
+ if( blue1 ) { blue1 = scale8_LEAVING_R1_DIRTY( blue1, brightness); blue1++; }
+ cleanup_R1();
+ } else {
+ red1 = 0;
+ green1 = 0;
+ blue1 = 0;
+ }
}
-
+
return CRGB( red1, green1, blue1);
}
@@ -600,7 +783,11 @@ CRGB ColorFromPalette( const CRGBPalette256& pal, uint8_t index, uint8_t brightn
uint8_t blue = entry->blue;
if( brightness != 255) {
- nscale8x3_video( red, green, blue, brightness);
+ brightness++; // adjust for rounding
+ red = scale8_video_LEAVING_R1_DIRTY( red, brightness);
+ green = scale8_video_LEAVING_R1_DIRTY( green, brightness);
+ blue = scale8_video_LEAVING_R1_DIRTY( blue, brightness);
+ cleanup_R1();
}
return CRGB( red, green, blue);
@@ -609,7 +796,8 @@ CRGB ColorFromPalette( const CRGBPalette256& pal, uint8_t index, uint8_t brightn
CHSV ColorFromPalette( const struct CHSVPalette16& pal, uint8_t index, uint8_t brightness, TBlendType blendType)
{
- uint8_t hi4 = index >> 4;
+ // hi4 = index >> 4;
+ uint8_t hi4 = lsrX4(index);
uint8_t lo4 = index & 0x0F;
// CRGB rgb1 = pal[ hi4];
@@ -690,6 +878,95 @@ CHSV ColorFromPalette( const struct CHSVPalette16& pal, uint8_t index, uint8_t b
}
+CHSV ColorFromPalette( const struct CHSVPalette32& pal, uint8_t index, uint8_t brightness, TBlendType blendType)
+{
+ uint8_t hi5 = index;
+#if defined(__AVR__)
+ hi5 /= 2;
+ hi5 /= 2;
+ hi5 /= 2;
+#else
+ hi5 >>= 3;
+#endif
+ uint8_t lo3 = index & 0x07;
+
+ uint8_t hi5XsizeofCHSV = hi5 * sizeof(CHSV);
+ const CHSV* entry = (CHSV*)( (uint8_t*)(&(pal[0])) + hi5XsizeofCHSV);
+
+ uint8_t hue1 = entry->hue;
+ uint8_t sat1 = entry->sat;
+ uint8_t val1 = entry->val;
+
+ uint8_t blend = lo3 && (blendType != NOBLEND);
+
+ if( blend ) {
+
+ if( hi5 == 31 ) {
+ entry = &(pal[0]);
+ } else {
+ entry++;
+ }
+
+ uint8_t f2 = lo3 << 5;
+ uint8_t f1 = 255 - f2;
+
+ uint8_t hue2 = entry->hue;
+ uint8_t sat2 = entry->sat;
+ uint8_t val2 = entry->val;
+
+ // Now some special casing for blending to or from
+ // either black or white. Black and white don't have
+ // proper 'hue' of their own, so when ramping from
+ // something else to/from black/white, we set the 'hue'
+ // of the black/white color to be the same as the hue
+ // of the other color, so that you get the expected
+ // brightness or saturation ramp, with hue staying
+ // constant:
+
+ // If we are starting from white (sat=0)
+ // or black (val=0), adopt the target hue.
+ if( sat1 == 0 || val1 == 0) {
+ hue1 = hue2;
+ }
+
+ // If we are ending at white (sat=0)
+ // or black (val=0), adopt the starting hue.
+ if( sat2 == 0 || val2 == 0) {
+ hue2 = hue1;
+ }
+
+
+ sat1 = scale8_LEAVING_R1_DIRTY( sat1, f1);
+ val1 = scale8_LEAVING_R1_DIRTY( val1, f1);
+
+ sat2 = scale8_LEAVING_R1_DIRTY( sat2, f2);
+ val2 = scale8_LEAVING_R1_DIRTY( val2, f2);
+
+ // cleanup_R1();
+
+ // These sums can't overflow, so no qadd8 needed.
+ sat1 += sat2;
+ val1 += val2;
+
+ uint8_t deltaHue = (uint8_t)(hue2 - hue1);
+ if( deltaHue & 0x80 ) {
+ // go backwards
+ hue1 -= scale8( 255 - deltaHue, f2);
+ } else {
+ // go forwards
+ hue1 += scale8( deltaHue, f2);
+ }
+
+ cleanup_R1();
+ }
+
+ if( brightness != 255) {
+ val1 = scale8_video( val1, brightness);
+ }
+
+ return CHSV( hue1, sat1, val1);
+}
+
CHSV ColorFromPalette( const struct CHSVPalette256& pal, uint8_t index, uint8_t brightness, TBlendType)
{
CHSV hsv = *( &(pal[0]) + index );
@@ -716,6 +993,41 @@ void UpscalePalette(const struct CHSVPalette16& srcpal16, struct CHSVPalette256&
}
}
+
+void UpscalePalette(const struct CRGBPalette16& srcpal16, struct CRGBPalette32& destpal32)
+{
+ for( uint8_t i = 0; i < 16; i++) {
+ uint8_t j = i * 2;
+ destpal32[j+0] = srcpal16[i];
+ destpal32[j+1] = srcpal16[i];
+ }
+}
+
+void UpscalePalette(const struct CHSVPalette16& srcpal16, struct CHSVPalette32& destpal32)
+{
+ for( uint8_t i = 0; i < 16; i++) {
+ uint8_t j = i * 2;
+ destpal32[j+0] = srcpal16[i];
+ destpal32[j+1] = srcpal16[i];
+ }
+}
+
+void UpscalePalette(const struct CRGBPalette32& srcpal32, struct CRGBPalette256& destpal256)
+{
+ for( int i = 0; i < 256; i++) {
+ destpal256[(uint8_t)(i)] = ColorFromPalette( srcpal32, i);
+ }
+}
+
+void UpscalePalette(const struct CHSVPalette32& srcpal32, struct CHSVPalette256& destpal256)
+{
+ for( int i = 0; i < 256; i++) {
+ destpal256[(uint8_t)(i)] = ColorFromPalette( srcpal32, i);
+ }
+}
+
+
+
#if 0
// replaced by PartyColors_p
void SetupPartyColors(CRGBPalette16& pal)
diff --git a/colorutils.h b/colorutils.h
index f27e0f4c..18a052fb 100644
--- a/colorutils.h
+++ b/colorutils.h
@@ -4,6 +4,7 @@
///@file colorutils.h
/// functions for color fill, paletters, blending, and more
+#include "FastLED.h"
#include "pixeltypes.h"
#include "fastled_progmem.h"
@@ -391,12 +392,17 @@ CRGB HeatColor( uint8_t temperature);
//
class CRGBPalette16;
+class CRGBPalette32;
class CRGBPalette256;
class CHSVPalette16;
+class CHSVPalette32;
class CHSVPalette256;
typedef uint32_t TProgmemRGBPalette16[16];
typedef uint32_t TProgmemHSVPalette16[16];
#define TProgmemPalette16 TProgmemRGBPalette16
+typedef uint32_t TProgmemRGBPalette32[32];
+typedef uint32_t TProgmemHSVPalette32[32];
+#define TProgmemPalette32 TProgmemRGBPalette32
typedef const uint8_t TProgmemRGBGradientPalette_byte ;
typedef const TProgmemRGBGradientPalette_byte *TProgmemRGBGradientPalette_bytes;
@@ -420,6 +426,14 @@ typedef TDynamicRGBGradientPalette_bytes TDynamicRGBGradientPalettePtr;
void UpscalePalette(const struct CRGBPalette16& srcpal16, struct CRGBPalette256& destpal256);
void UpscalePalette(const struct CHSVPalette16& srcpal16, struct CHSVPalette256& destpal256);
+// Convert a 16-entry palette to a 32-entry palette
+void UpscalePalette(const struct CRGBPalette16& srcpal16, struct CRGBPalette32& destpal32);
+void UpscalePalette(const struct CHSVPalette16& srcpal16, struct CHSVPalette32& destpal32);
+
+// Convert a 32-entry palette to a 256-entry palette
+void UpscalePalette(const struct CRGBPalette32& srcpal32, struct CRGBPalette256& destpal256);
+void UpscalePalette(const struct CHSVPalette32& srcpal32, struct CHSVPalette256& destpal256);
+
class CHSVPalette16 {
public:
@@ -648,11 +662,20 @@ public:
{
memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries));
}
+ CRGBPalette16( const CRGB rhs[16])
+ {
+ memmove8( &(entries[0]), &(rhs[0]), sizeof( entries));
+ }
CRGBPalette16& operator=( const CRGBPalette16& rhs)
{
memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries));
return *this;
}
+ CRGBPalette16& operator=( const CRGB rhs[16])
+ {
+ memmove8( &(entries[0]), &(rhs[0]), sizeof( entries));
+ return *this;
+ }
CRGBPalette16( const CHSVPalette16& rhs)
{
@@ -660,6 +683,12 @@ public:
entries[i] = rhs.entries[i]; // implicit HSV-to-RGB conversion
}
}
+ CRGBPalette16( const CHSV rhs[16])
+ {
+ for( uint8_t i = 0; i < 16; i++) {
+ entries[i] = rhs[i]; // implicit HSV-to-RGB conversion
+ }
+ }
CRGBPalette16& operator=( const CHSVPalette16& rhs)
{
for( uint8_t i = 0; i < 16; i++) {
@@ -667,6 +696,13 @@ public:
}
return *this;
}
+ CRGBPalette16& operator=( const CHSV rhs[16])
+ {
+ for( uint8_t i = 0; i < 16; i++) {
+ entries[i] = rhs[i]; // implicit HSV-to-RGB conversion
+ }
+ return *this;
+ }
CRGBPalette16( const TProgmemRGBPalette16& rhs)
{
@@ -871,6 +907,405 @@ public:
};
+
+
+class CHSVPalette32 {
+public:
+ CHSV entries[32];
+ CHSVPalette32() {};
+ CHSVPalette32( const CHSV& c00,const CHSV& c01,const CHSV& c02,const CHSV& c03,
+ const CHSV& c04,const CHSV& c05,const CHSV& c06,const CHSV& c07,
+ const CHSV& c08,const CHSV& c09,const CHSV& c10,const CHSV& c11,
+ const CHSV& c12,const CHSV& c13,const CHSV& c14,const CHSV& c15 )
+ {
+ for( uint8_t i = 0; i < 2; i++) {
+ entries[0+i]=c00; entries[2+i]=c01; entries[4+i]=c02; entries[6+i]=c03;
+ entries[8+i]=c04; entries[10+i]=c05; entries[12+i]=c06; entries[14+i]=c07;
+ entries[16+i]=c08; entries[18+i]=c09; entries[20+i]=c10; entries[22+i]=c11;
+ entries[24+i]=c12; entries[26+i]=c13; entries[28+i]=c14; entries[30+i]=c15;
+ }
+ };
+
+ CHSVPalette32( const CHSVPalette32& rhs)
+ {
+ memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries));
+ }
+ CHSVPalette32& operator=( const CHSVPalette32& rhs)
+ {
+ memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries));
+ return *this;
+ }
+
+ CHSVPalette32( const TProgmemHSVPalette32& rhs)
+ {
+ for( uint8_t i = 0; i < 32; i++) {
+ CRGB xyz = FL_PGM_READ_DWORD_NEAR( rhs + i);
+ entries[i].hue = xyz.red;
+ entries[i].sat = xyz.green;
+ entries[i].val = xyz.blue;
+ }
+ }
+ CHSVPalette32& operator=( const TProgmemHSVPalette32& rhs)
+ {
+ for( uint8_t i = 0; i < 32; i++) {
+ CRGB xyz = FL_PGM_READ_DWORD_NEAR( rhs + i);
+ entries[i].hue = xyz.red;
+ entries[i].sat = xyz.green;
+ entries[i].val = xyz.blue;
+ }
+ return *this;
+ }
+
+ inline CHSV& operator[] (uint8_t x) __attribute__((always_inline))
+ {
+ return entries[x];
+ }
+ inline const CHSV& operator[] (uint8_t x) const __attribute__((always_inline))
+ {
+ return entries[x];
+ }
+
+ inline CHSV& operator[] (int x) __attribute__((always_inline))
+ {
+ return entries[(uint8_t)x];
+ }
+ inline const CHSV& operator[] (int x) const __attribute__((always_inline))
+ {
+ return entries[(uint8_t)x];
+ }
+
+ operator CHSV*()
+ {
+ return &(entries[0]);
+ }
+
+ bool operator==( const CHSVPalette32 rhs)
+ {
+ const uint8_t* p = (const uint8_t*)(&(this->entries[0]));
+ const uint8_t* q = (const uint8_t*)(&(rhs.entries[0]));
+ if( p == q) return true;
+ for( uint8_t i = 0; i < (sizeof( entries)); i++) {
+ if( *p != *q) return false;
+ p++;
+ q++;
+ }
+ return true;
+ }
+ bool operator!=( const CHSVPalette32 rhs)
+ {
+ return !( *this == rhs);
+ }
+
+ CHSVPalette32( const CHSV& c1)
+ {
+ fill_solid( &(entries[0]), 32, c1);
+ }
+ CHSVPalette32( const CHSV& c1, const CHSV& c2)
+ {
+ fill_gradient( &(entries[0]), 32, c1, c2);
+ }
+ CHSVPalette32( const CHSV& c1, const CHSV& c2, const CHSV& c3)
+ {
+ fill_gradient( &(entries[0]), 32, c1, c2, c3);
+ }
+ CHSVPalette32( const CHSV& c1, const CHSV& c2, const CHSV& c3, const CHSV& c4)
+ {
+ fill_gradient( &(entries[0]), 32, c1, c2, c3, c4);
+ }
+
+};
+
+class CRGBPalette32 {
+public:
+ CRGB entries[32];
+ CRGBPalette32() {};
+ CRGBPalette32( const CRGB& c00,const CRGB& c01,const CRGB& c02,const CRGB& c03,
+ const CRGB& c04,const CRGB& c05,const CRGB& c06,const CRGB& c07,
+ const CRGB& c08,const CRGB& c09,const CRGB& c10,const CRGB& c11,
+ const CRGB& c12,const CRGB& c13,const CRGB& c14,const CRGB& c15 )
+ {
+ for( uint8_t i = 0; i < 2; i++) {
+ entries[0+i]=c00; entries[2+i]=c01; entries[4+i]=c02; entries[6+i]=c03;
+ entries[8+i]=c04; entries[10+i]=c05; entries[12+i]=c06; entries[14+i]=c07;
+ entries[16+i]=c08; entries[18+i]=c09; entries[20+i]=c10; entries[22+i]=c11;
+ entries[24+i]=c12; entries[26+i]=c13; entries[28+i]=c14; entries[30+i]=c15;
+ }
+ };
+
+ CRGBPalette32( const CRGBPalette32& rhs)
+ {
+ memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries));
+ }
+ CRGBPalette32( const CRGB rhs[32])
+ {
+ memmove8( &(entries[0]), &(rhs[0]), sizeof( entries));
+ }
+ CRGBPalette32& operator=( const CRGBPalette32& rhs)
+ {
+ memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries));
+ return *this;
+ }
+ CRGBPalette32& operator=( const CRGB rhs[32])
+ {
+ memmove8( &(entries[0]), &(rhs[0]), sizeof( entries));
+ return *this;
+ }
+
+ CRGBPalette32( const CHSVPalette32& rhs)
+ {
+ for( uint8_t i = 0; i < 32; i++) {
+ entries[i] = rhs.entries[i]; // implicit HSV-to-RGB conversion
+ }
+ }
+ CRGBPalette32( const CHSV rhs[32])
+ {
+ for( uint8_t i = 0; i < 32; i++) {
+ entries[i] = rhs[i]; // implicit HSV-to-RGB conversion
+ }
+ }
+ CRGBPalette32& operator=( const CHSVPalette32& rhs)
+ {
+ for( uint8_t i = 0; i < 32; i++) {
+ entries[i] = rhs.entries[i]; // implicit HSV-to-RGB conversion
+ }
+ return *this;
+ }
+ CRGBPalette32& operator=( const CHSV rhs[32])
+ {
+ for( uint8_t i = 0; i < 32; i++) {
+ entries[i] = rhs[i]; // implicit HSV-to-RGB conversion
+ }
+ return *this;
+ }
+
+ CRGBPalette32( const TProgmemRGBPalette32& rhs)
+ {
+ for( uint8_t i = 0; i < 32; i++) {
+ entries[i] = FL_PGM_READ_DWORD_NEAR( rhs + i);
+ }
+ }
+ CRGBPalette32& operator=( const TProgmemRGBPalette32& rhs)
+ {
+ for( uint8_t i = 0; i < 32; i++) {
+ entries[i] = FL_PGM_READ_DWORD_NEAR( rhs + i);
+ }
+ return *this;
+ }
+
+ bool operator==( const CRGBPalette32 rhs)
+ {
+ const uint8_t* p = (const uint8_t*)(&(this->entries[0]));
+ const uint8_t* q = (const uint8_t*)(&(rhs.entries[0]));
+ if( p == q) return true;
+ for( uint8_t i = 0; i < (sizeof( entries)); i++) {
+ if( *p != *q) return false;
+ p++;
+ q++;
+ }
+ return true;
+ }
+ bool operator!=( const CRGBPalette32 rhs)
+ {
+ return !( *this == rhs);
+ }
+
+ inline CRGB& operator[] (uint8_t x) __attribute__((always_inline))
+ {
+ return entries[x];
+ }
+ inline const CRGB& operator[] (uint8_t x) const __attribute__((always_inline))
+ {
+ return entries[x];
+ }
+
+ inline CRGB& operator[] (int x) __attribute__((always_inline))
+ {
+ return entries[(uint8_t)x];
+ }
+ inline const CRGB& operator[] (int x) const __attribute__((always_inline))
+ {
+ return entries[(uint8_t)x];
+ }
+
+ operator CRGB*()
+ {
+ return &(entries[0]);
+ }
+
+ CRGBPalette32( const CHSV& c1)
+ {
+ fill_solid( &(entries[0]), 32, c1);
+ }
+ CRGBPalette32( const CHSV& c1, const CHSV& c2)
+ {
+ fill_gradient( &(entries[0]), 32, c1, c2);
+ }
+ CRGBPalette32( const CHSV& c1, const CHSV& c2, const CHSV& c3)
+ {
+ fill_gradient( &(entries[0]), 32, c1, c2, c3);
+ }
+ CRGBPalette32( const CHSV& c1, const CHSV& c2, const CHSV& c3, const CHSV& c4)
+ {
+ fill_gradient( &(entries[0]), 32, c1, c2, c3, c4);
+ }
+
+ CRGBPalette32( const CRGB& c1)
+ {
+ fill_solid( &(entries[0]), 32, c1);
+ }
+ CRGBPalette32( const CRGB& c1, const CRGB& c2)
+ {
+ fill_gradient_RGB( &(entries[0]), 32, c1, c2);
+ }
+ CRGBPalette32( const CRGB& c1, const CRGB& c2, const CRGB& c3)
+ {
+ fill_gradient_RGB( &(entries[0]), 32, c1, c2, c3);
+ }
+ CRGBPalette32( const CRGB& c1, const CRGB& c2, const CRGB& c3, const CRGB& c4)
+ {
+ fill_gradient_RGB( &(entries[0]), 32, c1, c2, c3, c4);
+ }
+
+
+ CRGBPalette32( const CRGBPalette16& rhs16)
+ {
+ UpscalePalette( rhs16, *this);
+ }
+ CRGBPalette32& operator=( const CRGBPalette16& rhs16)
+ {
+ UpscalePalette( rhs16, *this);
+ return *this;
+ }
+
+ CRGBPalette32( const TProgmemRGBPalette16& rhs)
+ {
+ CRGBPalette16 p16(rhs);
+ *this = p16;
+ }
+ CRGBPalette32& operator=( const TProgmemRGBPalette16& rhs)
+ {
+ CRGBPalette16 p16(rhs);
+ *this = p16;
+ return *this;
+ }
+
+
+ // Gradient palettes are loaded into CRGB16Palettes in such a way
+ // that, if possible, every color represented in the gradient palette
+ // is also represented in the CRGBPalette32.
+ // For example, consider a gradient palette that is all black except
+ // for a single, one-element-wide (1/256th!) spike of red in the middle:
+ // 0, 0,0,0
+ // 124, 0,0,0
+ // 125, 255,0,0 // one 1/256th-palette-wide red stripe
+ // 126, 0,0,0
+ // 255, 0,0,0
+ // A naive conversion of this 256-element palette to a 16-element palette
+ // might accidentally completely eliminate the red spike, rendering the
+ // palette completely black.
+ // However, the conversions provided here would attempt to include a
+ // the red stripe in the output, more-or-less as faithfully as possible.
+ // So in this case, the resulting CRGBPalette32 palette would have a red
+ // stripe in the middle which was 1/16th of a palette wide -- the
+ // narrowest possible in a CRGBPalette32.
+ // This means that the relative width of stripes in a CRGBPalette32
+ // will be, by definition, different from the widths in the gradient
+ // palette. This code attempts to preserve "all the colors", rather than
+ // the exact stripe widths at the expense of dropping some colors.
+ CRGBPalette32( TProgmemRGBGradientPalette_bytes progpal )
+ {
+ *this = progpal;
+ }
+ CRGBPalette32& operator=( TProgmemRGBGradientPalette_bytes progpal )
+ {
+ TRGBGradientPaletteEntryUnion* progent = (TRGBGradientPaletteEntryUnion*)(progpal);
+ TRGBGradientPaletteEntryUnion u;
+
+ // Count entries
+ uint8_t count = 0;
+ do {
+ u.dword = FL_PGM_READ_DWORD_NEAR(progent + count);
+ count++;;
+ } while ( u.index != 255);
+
+ int8_t lastSlotUsed = -1;
+
+ u.dword = FL_PGM_READ_DWORD_NEAR( progent);
+ CRGB rgbstart( u.r, u.g, u.b);
+
+ int indexstart = 0;
+ uint8_t istart8 = 0;
+ uint8_t iend8 = 0;
+ while( indexstart < 255) {
+ progent++;
+ u.dword = FL_PGM_READ_DWORD_NEAR( progent);
+ int indexend = u.index;
+ CRGB rgbend( u.r, u.g, u.b);
+ istart8 = indexstart / 8;
+ iend8 = indexend / 8;
+ if( count < 16) {
+ if( (istart8 <= lastSlotUsed) && (lastSlotUsed < 31)) {
+ istart8 = lastSlotUsed + 1;
+ if( iend8 < istart8) {
+ iend8 = istart8;
+ }
+ }
+ lastSlotUsed = iend8;
+ }
+ fill_gradient_RGB( &(entries[0]), istart8, rgbstart, iend8, rgbend);
+ indexstart = indexend;
+ rgbstart = rgbend;
+ }
+ return *this;
+ }
+ CRGBPalette32& loadDynamicGradientPalette( TDynamicRGBGradientPalette_bytes gpal )
+ {
+ TRGBGradientPaletteEntryUnion* ent = (TRGBGradientPaletteEntryUnion*)(gpal);
+ TRGBGradientPaletteEntryUnion u;
+
+ // Count entries
+ uint8_t count = 0;
+ do {
+ u = *(ent + count);
+ count++;;
+ } while ( u.index != 255);
+
+ int8_t lastSlotUsed = -1;
+
+
+ u = *ent;
+ CRGB rgbstart( u.r, u.g, u.b);
+
+ int indexstart = 0;
+ uint8_t istart8 = 0;
+ uint8_t iend8 = 0;
+ while( indexstart < 255) {
+ ent++;
+ u = *ent;
+ int indexend = u.index;
+ CRGB rgbend( u.r, u.g, u.b);
+ istart8 = indexstart / 8;
+ iend8 = indexend / 8;
+ if( count < 16) {
+ if( (istart8 <= lastSlotUsed) && (lastSlotUsed < 31)) {
+ istart8 = lastSlotUsed + 1;
+ if( iend8 < istart8) {
+ iend8 = istart8;
+ }
+ }
+ lastSlotUsed = iend8;
+ }
+ fill_gradient_RGB( &(entries[0]), istart8, rgbstart, iend8, rgbend);
+ indexstart = indexend;
+ rgbstart = rgbend;
+ }
+ return *this;
+ }
+
+};
+
+
+
class CRGBPalette256 {
public:
CRGB entries[256];
@@ -889,11 +1324,20 @@ public:
{
memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries));
}
+ CRGBPalette256( const CRGB rhs[256])
+ {
+ memmove8( &(entries[0]), &(rhs[0]), sizeof( entries));
+ }
CRGBPalette256& operator=( const CRGBPalette256& rhs)
{
memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries));
return *this;
}
+ CRGBPalette256& operator=( const CRGB rhs[256])
+ {
+ memmove8( &(entries[0]), &(rhs[0]), sizeof( entries));
+ return *this;
+ }
CRGBPalette256( const CHSVPalette256& rhs)
{
@@ -901,6 +1345,12 @@ public:
entries[i] = rhs.entries[i]; // implicit HSV-to-RGB conversion
}
}
+ CRGBPalette256( const CHSV rhs[256])
+ {
+ for( int i = 0; i < 256; i++) {
+ entries[i] = rhs[i]; // implicit HSV-to-RGB conversion
+ }
+ }
CRGBPalette256& operator=( const CHSVPalette256& rhs)
{
for( int i = 0; i < 256; i++) {
@@ -908,6 +1358,13 @@ public:
}
return *this;
}
+ CRGBPalette256& operator=( const CHSV rhs[256])
+ {
+ for( int i = 0; i < 256; i++) {
+ entries[i] = rhs[i]; // implicit HSV-to-RGB conversion
+ }
+ return *this;
+ }
CRGBPalette256( const CRGBPalette16& rhs16)
{
@@ -1051,7 +1508,6 @@ public:
-
typedef enum { NOBLEND=0, LINEARBLEND=1 } TBlendType;
CRGB ColorFromPalette( const CRGBPalette16& pal,
@@ -1079,6 +1535,21 @@ CHSV ColorFromPalette( const CHSVPalette256& pal,
uint8_t brightness=255,
TBlendType blendType=NOBLEND );
+CRGB ColorFromPalette( const CRGBPalette32& pal,
+ uint8_t index,
+ uint8_t brightness=255,
+ TBlendType blendType=LINEARBLEND);
+
+CRGB ColorFromPalette( const TProgmemRGBPalette32& pal,
+ uint8_t index,
+ uint8_t brightness=255,
+ TBlendType blendType=LINEARBLEND);
+
+CHSV ColorFromPalette( const CHSVPalette32& pal,
+ uint8_t index,
+ uint8_t brightness=255,
+ TBlendType blendType=LINEARBLEND);
+
// Fill a range of LEDs with a sequece of entryies from a palette
template <typename PALETTE>
diff --git a/controller.h b/controller.h
index bb063cdf..06d3c47e 100644
--- a/controller.h
+++ b/controller.h
@@ -4,6 +4,7 @@
///@file controller.h
/// base definitions used by led controllers for writing out led data
+#include "FastLED.h"
#include "led_sysdefs.h"
#include "pixeltypes.h"
#include "color.h"
diff --git a/cpp_compat.h b/cpp_compat.h
index 94674170..ab5b773a 100644
--- a/cpp_compat.h
+++ b/cpp_compat.h
@@ -1,6 +1,8 @@
#ifndef __INC_CPP_COMPAT_H
#define __INC_CPP_COMPAT_H
+#include "FastLED.h"
+
#if __cplusplus <= 199711L
#define static_assert(expression, message)
diff --git a/dmx.h b/dmx.h
index 6b464e30..245c7cfc 100644
--- a/dmx.h
+++ b/dmx.h
@@ -1,6 +1,7 @@
#ifndef __INC_DMX_H
#define __INC_DMX_H
+#include "FastLED.h"
#ifdef DmxSimple_h
#include<DmxSimple.h>
diff --git a/docs/.Doxyfile.swp b/docs/.Doxyfile.swp
deleted file mode 100644
index d223ba7d..00000000
--- a/docs/.Doxyfile.swp
+++ /dev/null
Binary files differ
diff --git a/examples/DemoReel100/DemoReel100.ino b/examples/DemoReel100/DemoReel100.ino
index 0f57cad7..ffa3a9fd 100644
--- a/examples/DemoReel100/DemoReel100.ino
+++ b/examples/DemoReel100/DemoReel100.ino
@@ -11,7 +11,7 @@ FASTLED_USING_NAMESPACE
//
// -Mark Kriegsman, December 2014
-#if FASTLED_VERSION < 3001000
+#if defined(FASTLED_VERSION) && (FASTLED_VERSION < 3001000)
#warning "Requires FastLED 3.1 or later; check github for latest code."
#endif
diff --git a/examples/RGBSetDemo/RGBSetDemo.ino b/examples/RGBSetDemo/RGBSetDemo.ino
new file mode 100644
index 00000000..3b9ef24e
--- /dev/null
+++ b/examples/RGBSetDemo/RGBSetDemo.ino
@@ -0,0 +1,22 @@
+#include<FastLED.h>
+#define NUM_LEDS 40
+
+CRGBArray<NUM_LEDS> leds;
+
+void setup() { FastLED.addLeds<NEOPIXEL,6>(leds, NUM_LEDS); }
+
+void loop(){
+ static uint8_t hue;
+ for(int i = 0; i < NUM_LEDS/2; i++) {
+ // fade everything out
+ leds.fadeToBlackBy(40);
+
+ // let's set an led value
+ leds[i] = CHSV(hue++,255,255);
+
+ // now, let's first 20 leds to the top 20 leds,
+ leds(NUM_LEDS/2,NUM_LEDS-1) = leds(NUM_LEDS/2 - 1 ,0);
+ FastLED.delay(33);
+ }
+}
+
diff --git a/examples/XYMatrix/XYMatrix.ino b/examples/XYMatrix/XYMatrix.ino
index ff0c5d14..53c21411 100644
--- a/examples/XYMatrix/XYMatrix.ino
+++ b/examples/XYMatrix/XYMatrix.ino
@@ -121,7 +121,7 @@ uint16_t XY( uint8_t x, uint8_t y)
// it, "leds_plus_safety_pixel". Then declare "leds" as a pointer to
// that array, but starting with the 2nd element (id=1) of that array:
// CRGB leds_with_safety_pixel[41];
-// const CRGB* leds( leds_plus_safety_pixel + 1);
+// CRGB* const leds( leds_plus_safety_pixel + 1);
// Then you use the "leds" array as you normally would.
// Now "leds[0..N]" are aliases for "leds_plus_safety_pixel[1..(N+1)]",
// AND leds[-1] is now a legitimate and safe alias for leds_plus_safety_pixel[0].
@@ -150,7 +150,7 @@ uint16_t XY( uint8_t x, uint8_t y)
#define NUM_LEDS (kMatrixWidth * kMatrixHeight)
CRGB leds_plus_safety_pixel[ NUM_LEDS + 1];
-CRGB* leds( leds_plus_safety_pixel + 1);
+CRGB* const leds( leds_plus_safety_pixel + 1);
uint16_t XYsafe( uint8_t x, uint8_t y)
{
@@ -194,4 +194,3 @@ void setup() {
FastLED.addLeds<CHIPSET, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalSMD5050);
FastLED.setBrightness( BRIGHTNESS );
}
-
diff --git a/fastled_config.h b/fastled_config.h
index 42023f53..aa510e58 100644
--- a/fastled_config.h
+++ b/fastled_config.h
@@ -1,6 +1,8 @@
#ifndef __INC_FASTLED_CONFIG_H
#define __INC_FASTLED_CONFIG_H
+#include "FastLED.h"
+
///@file fastled_config.h
/// contains definitions that can be used to configure FastLED at compile time
@@ -19,4 +21,12 @@
// #define FASTLED_ALLOW_INTERRUPTS 1
// #define FASTLED_ALLOW_INTERRUPTS 0
+// Use this to allow some integer overflows/underflows in the inoise functions.
+// The original implementions allowed this, and had some discontinuties in the noise
+// output. It's technically an implementation bug, and was fixed, but you may wish
+// to preserve the old look and feel of the inoise functions in your existing animations.
+// The default is 0: NO overflow, and 'continuous' noise output, aka the fixed way.
+// #define FASTLED_NOISE_ALLOW_AVERAGE_TO_OVERFLOW 0
+// #define FASTLED_NOISE_ALLOW_AVERAGE_TO_OVERFLOW 1
+
#endif
diff --git a/fastled_delay.h b/fastled_delay.h
index 5df7609d..f16d322e 100644
--- a/fastled_delay.h
+++ b/fastled_delay.h
@@ -1,6 +1,8 @@
#ifndef __INC_FL_DELAY_H
#define __INC_FL_DELAY_H
+#include "FastLED.h"
+
///@file fastled_delay.h
///Utility functions and classes for managing delaycycles
@@ -41,6 +43,11 @@ public:
// predeclaration to not upset the compiler
template<int CYCLES> inline void delaycycles();
+template<int CYCLES> inline void delaycycles_min1() {
+ delaycycles<1>();
+ delaycycles<CYCLES-1>();
+}
+
// TODO: ARM version of _delaycycles_
@@ -90,6 +97,10 @@ template<int CYCLES> __attribute__((always_inline)) inline void delaycycles() {
// pre-instantiations for values small enough to not need the loop, as well as sanity holders
// for some negative values.
+template<> __attribute__((always_inline)) inline void delaycycles<-10>() {}
+template<> __attribute__((always_inline)) inline void delaycycles<-9>() {}
+template<> __attribute__((always_inline)) inline void delaycycles<-8>() {}
+template<> __attribute__((always_inline)) inline void delaycycles<-7>() {}
template<> __attribute__((always_inline)) inline void delaycycles<-6>() {}
template<> __attribute__((always_inline)) inline void delaycycles<-5>() {}
template<> __attribute__((always_inline)) inline void delaycycles<-4>() {}
diff --git a/fastled_progmem.h b/fastled_progmem.h
index f7cedc02..342fe6eb 100644
--- a/fastled_progmem.h
+++ b/fastled_progmem.h
@@ -1,6 +1,8 @@
#ifndef __INC_FL_PROGMEM_H
#define __INC_FL_PROGMEM_H
+#include "FastLED.h"
+
///@file fastled_progmem.h
/// wrapper definitions to allow seamless use of PROGMEM in environmens that have it
diff --git a/fastpin.h b/fastpin.h
index e00ecd69..6f4bdf06 100644
--- a/fastpin.h
+++ b/fastpin.h
@@ -1,6 +1,8 @@
#ifndef __INC_FASTPIN_H
#define __INC_FASTPIN_H
+#include "FastLED.h"
+
#include "led_sysdefs.h"
#pragma GCC diagnostic push
@@ -36,8 +38,8 @@ class Pin : public Selectable {
void _init() {
mPinMask = digitalPinToBitMask(mPin);
- mPort = portOutputRegister(digitalPinToPort(mPin));
- mInPort = portInputRegister(digitalPinToPort(mPin));
+ mPort = (volatile RwReg*)portOutputRegister(digitalPinToPort(mPin));
+ mInPort = (volatile RoReg*)portInputRegister(digitalPinToPort(mPin));
}
public:
Pin(int pin) : mPin(pin) { _init(); }
diff --git a/fastspi.h b/fastspi.h
index 24bf26fa..db74eb87 100644
--- a/fastspi.h
+++ b/fastspi.h
@@ -1,6 +1,8 @@
#ifndef __INC_FASTSPI_H
#define __INC_FASTSPI_H
+#include "FastLED.h"
+
#include "controller.h"
#include "lib8tion.h"
diff --git a/fastspi_bitbang.h b/fastspi_bitbang.h
index 65c2a5d8..6621668a 100644
--- a/fastspi_bitbang.h
+++ b/fastspi_bitbang.h
@@ -1,6 +1,8 @@
#ifndef __INC_FASTSPI_BITBANG_H
#define __INC_FASTSPI_BITBANG_H
+#include "FastLED.h"
+
#include "fastled_delay.h"
FASTLED_NAMESPACE_BEGIN
@@ -109,20 +111,26 @@ private:
}
public:
- #define SPI_DELAY delaycycles<1+((SPI_SPEED-2) / 2)>();
- #define SPI_DELAY_HALF delaycycles<1+ ((SPI_SPEED-4) / 4)>();
+
+ // We want to make sure that the clock pulse is held high for a nininum of 35ns.
+ #define MIN_DELAY (NS(35) - 3)
+
+ #define CLOCK_HI_DELAY delaycycles<MIN_DELAY>(); delaycycles<(((SPI_SPEED-6) / 2) - MIN_DELAY)>();
+ #define CLOCK_LO_DELAY delaycycles<(((SPI_SPEED-6) / 4))>();
// write the BIT'th bit out via spi, setting the data pin then strobing the clcok
template <uint8_t BIT> __attribute__((always_inline, hot)) inline static void writeBit(uint8_t b) {
+ //cli();
if(b & (1 << BIT)) {
FastPin<DATA_PIN>::hi();
- FastPin<CLOCK_PIN>::hi(); SPI_DELAY;
- FastPin<CLOCK_PIN>::lo(); SPI_DELAY;
+ FastPin<CLOCK_PIN>::hi(); CLOCK_HI_DELAY;
+ FastPin<CLOCK_PIN>::lo(); CLOCK_LO_DELAY;
} else {
FastPin<DATA_PIN>::lo();
- FastPin<CLOCK_PIN>::hi(); SPI_DELAY;
- FastPin<CLOCK_PIN>::lo(); SPI_DELAY;
+ FastPin<CLOCK_PIN>::hi(); CLOCK_HI_DELAY;
+ FastPin<CLOCK_PIN>::lo(); CLOCK_LO_DELAY;
}
+ //sei();
}
private:
@@ -130,12 +138,12 @@ private:
template <uint8_t BIT> __attribute__((always_inline)) inline static void writeBit(uint8_t b, clock_ptr_t clockpin, data_ptr_t datapin) {
if(b & (1 << BIT)) {
FastPin<DATA_PIN>::hi(datapin);
- FastPin<CLOCK_PIN>::hi(clockpin); SPI_DELAY;
- FastPin<CLOCK_PIN>::lo(clockpin); SPI_DELAY;
+ FastPin<CLOCK_PIN>::hi(clockpin); CLOCK_HI_DELAY;
+ FastPin<CLOCK_PIN>::lo(clockpin); CLOCK_LO_DELAY;
} else {
FastPin<DATA_PIN>::lo(datapin);
- FastPin<CLOCK_PIN>::hi(clockpin); SPI_DELAY;
- FastPin<CLOCK_PIN>::lo(clockpin); SPI_DELAY;
+ FastPin<CLOCK_PIN>::hi(clockpin); CLOCK_HI_DELAY;
+ FastPin<CLOCK_PIN>::lo(clockpin); CLOCK_LO_DELAY;
}
}
@@ -147,13 +155,13 @@ private:
// // only need to explicitly set clock hi if clock and data are on different ports
if(b & (1 << BIT)) {
FastPin<DATA_PIN>::fastset(datapin, hival);
- FastPin<CLOCK_PIN>::fastset(clockpin, hiclock); SPI_DELAY;
- FastPin<CLOCK_PIN>::fastset(clockpin, loclock); SPI_DELAY;
+ FastPin<CLOCK_PIN>::fastset(clockpin, hiclock); CLOCK_HI_DELAY;
+ FastPin<CLOCK_PIN>::fastset(clockpin, loclock); CLOCK_LO_DELAY;
} else {
// NOP;
FastPin<DATA_PIN>::fastset(datapin, loval);
- FastPin<CLOCK_PIN>::fastset(clockpin, hiclock); SPI_DELAY;
- FastPin<CLOCK_PIN>::fastset(clockpin, loclock); SPI_DELAY;
+ FastPin<CLOCK_PIN>::fastset(clockpin, hiclock); CLOCK_HI_DELAY;
+ FastPin<CLOCK_PIN>::fastset(clockpin, loclock); CLOCK_LO_DELAY;
}
}
@@ -166,14 +174,14 @@ private:
writeBit<BIT>(b);
#else
if(b & (1 << BIT)) {
- FastPin<DATA_PIN>::fastset(clockdatapin, datahiclocklo); SPI_DELAY_HALF;
- FastPin<DATA_PIN>::fastset(clockdatapin, datahiclockhi); SPI_DELAY;
- FastPin<DATA_PIN>::fastset(clockdatapin, datahiclocklo); SPI_DELAY_HALF;
+ FastPin<DATA_PIN>::fastset(clockdatapin, datahiclocklo);
+ FastPin<DATA_PIN>::fastset(clockdatapin, datahiclockhi); CLOCK_HI_DELAY;
+ FastPin<DATA_PIN>::fastset(clockdatapin, datahiclocklo); CLOCK_LO_DELAY;
} else {
// NOP;
- FastPin<DATA_PIN>::fastset(clockdatapin, dataloclocklo); SPI_DELAY_HALF;
- FastPin<DATA_PIN>::fastset(clockdatapin, dataloclockhi); SPI_DELAY;
- FastPin<DATA_PIN>::fastset(clockdatapin, dataloclocklo); SPI_DELAY_HALF;
+ FastPin<DATA_PIN>::fastset(clockdatapin, dataloclocklo);
+ FastPin<DATA_PIN>::fastset(clockdatapin, dataloclockhi); CLOCK_HI_DELAY;
+ FastPin<DATA_PIN>::fastset(clockdatapin, dataloclocklo); CLOCK_LO_DELAY;
}
#endif
}
diff --git a/fastspi_nop.h b/fastspi_nop.h
index aa363394..5c5da010 100644
--- a/fastspi_nop.h
+++ b/fastspi_nop.h
@@ -1,6 +1,10 @@
#ifndef __INC_FASTSPI_NOP_H
#define __INC_FASTSPI_NOP_H
+#if 0 // Guard against the arduino ide idiotically including every header file
+
+#include "FastLED.h"
+
FASTLED_NAMESPACE_BEGIN
/// A nop/stub class, mostly to show the SPI methods that are needed/used by the various SPI chipset implementations. Should
@@ -57,3 +61,4 @@ public:
FASTLED_NAMESPACE_END
#endif
+#endif
diff --git a/fastspi_ref.h b/fastspi_ref.h
index 157ea2e3..f68e63ef 100644
--- a/fastspi_ref.h
+++ b/fastspi_ref.h
@@ -1,6 +1,9 @@
#ifndef __INC_FASTSPI_ARM_SAM_H
#define __INC_FASTSPI_ARM_SAM_H
+#if 0 // guard against the arduino ide idiotically including every header file
+#include "FastLED.h"
+
FASTLED_NAMESPACE_BEGIN
// A skeletal implementation of hardware SPI support. Fill in the necessary code for init, waiting, and writing. The rest of
@@ -87,3 +90,6 @@ public:
FASTLED_NAMESPACE_END
#endif
+
+#endif
+
diff --git a/fastspi_types.h b/fastspi_types.h
index 955ac938..5510bba8 100644
--- a/fastspi_types.h
+++ b/fastspi_types.h
@@ -1,6 +1,8 @@
#ifndef __INC_FASTSPI_TYPES_H
#define __INC_FASTSPI_TYPES_H
+#include "FastLED.h"
+
FASTLED_NAMESPACE_BEGIN
// Some helper macros for getting at mis-ordered byte values
diff --git a/hsv2rgb.cpp b/hsv2rgb.cpp
index 17c20c4c..49056d51 100644
--- a/hsv2rgb.cpp
+++ b/hsv2rgb.cpp
@@ -286,22 +286,22 @@ void hsv2rgb_rainbow( const CHSV& hsv, CRGB& rgb)
// Level Y2 is a strong boost.
const uint8_t Y1 = 1;
const uint8_t Y2 = 0;
-
+
// G2: Whether to divide all greens by two.
// Depends GREATLY on your particular LEDs
const uint8_t G2 = 0;
-
+
// Gscale: what to scale green down by.
// Depends GREATLY on your particular LEDs
const uint8_t Gscale = 0;
-
-
+
+
uint8_t hue = hsv.hue;
uint8_t sat = hsv.sat;
uint8_t val = hsv.val;
-
+
uint8_t offset = hue & 0x1F; // 0..31
-
+
// offset8 = offset * 8
uint8_t offset8 = offset;
{
@@ -319,11 +319,11 @@ void hsv2rgb_rainbow( const CHSV& hsv, CRGB& rgb)
offset8 <<= 3;
#endif
}
-
+
uint8_t third = scale8( offset8, (256 / 3));
-
+
uint8_t r, g, b;
-
+
if( ! (hue & 0x80) ) {
// 0XX
if( ! (hue & 0x40) ) {
@@ -397,7 +397,7 @@ void hsv2rgb_rainbow( const CHSV& hsv, CRGB& rgb)
uint8_t twothirds = scale8( offset8, ((256 * 2) / 3));
g = K171 - twothirds;
b = K85 + twothirds;
-
+
} else {
// 101
//case 5: // B -> P
@@ -405,7 +405,7 @@ void hsv2rgb_rainbow( const CHSV& hsv, CRGB& rgb)
g = 0;
FORCE_REFERENCE(g);
b = K255 - third;
-
+
}
} else {
if( ! (hue & 0x20) ) {
@@ -415,7 +415,7 @@ void hsv2rgb_rainbow( const CHSV& hsv, CRGB& rgb)
g = 0;
FORCE_REFERENCE(g);
b = K171 - third;
-
+
} else {
// 111
//case 7: // K -> R
@@ -423,38 +423,53 @@ void hsv2rgb_rainbow( const CHSV& hsv, CRGB& rgb)
g = 0;
FORCE_REFERENCE(g);
b = K85 - third;
-
+
}
}
}
-
+
// This is one of the good places to scale the green down,
// although the client can scale green down as well.
if( G2 ) g = g >> 1;
if( Gscale ) g = scale8_video_LEAVING_R1_DIRTY( g, Gscale);
-
+
// Scale down colors if we're desaturated at all
// and add the brightness_floor to r, g, and b.
if( sat != 255 ) {
-
- nscale8x3_video( r, g, b, sat);
-
- uint8_t desat = 255 - sat;
- desat = scale8( desat, desat);
-
- uint8_t brightness_floor = desat;
- r += brightness_floor;
- g += brightness_floor;
- b += brightness_floor;
+ if( sat == 0) {
+ r = 255; b = 255; g = 255;
+ } else {
+ //nscale8x3_video( r, g, b, sat);
+ if( r ) r = scale8_LEAVING_R1_DIRTY( r, sat) + 1;
+ if( g ) g = scale8_LEAVING_R1_DIRTY( g, sat) + 1;
+ if( b ) b = scale8_LEAVING_R1_DIRTY( b, sat) + 1;
+ cleanup_R1();
+
+ uint8_t desat = 255 - sat;
+ desat = scale8( desat, desat);
+
+ uint8_t brightness_floor = desat;
+ r += brightness_floor;
+ g += brightness_floor;
+ b += brightness_floor;
+ }
}
-
+
// Now scale everything down if we're at value < 255.
if( val != 255 ) {
-
+
val = scale8_video_LEAVING_R1_DIRTY( val, val);
- nscale8x3_video( r, g, b, val);
+ if( val == 0 ) {
+ r=0; g=0; b=0;
+ } else {
+ // nscale8x3_video( r, g, b, val);
+ if( r ) r = scale8_LEAVING_R1_DIRTY( r, val) + 1;
+ if( g ) g = scale8_LEAVING_R1_DIRTY( g, val) + 1;
+ if( b ) b = scale8_LEAVING_R1_DIRTY( b, val) + 1;
+ cleanup_R1();
+ }
}
-
+
// Here we have the old AVR "missing std X+n" problem again
// It turns out that fixing it winds up costing more than
// not fixing it.
@@ -498,41 +513,72 @@ CHSV rgb2hsv_approximate( const CRGB& rgb)
uint8_t g = rgb.g;
uint8_t b = rgb.b;
uint8_t h, s, v;
-
+
// find desaturation
uint8_t desat = 255;
if( r < desat) desat = r;
if( g < desat) desat = g;
if( b < desat) desat = b;
-
+
// remove saturation from all channels
r -= desat;
g -= desat;
b -= desat;
-
+
+ //Serial.print("desat="); Serial.print(desat); Serial.println("");
+
+ //uint8_t orig_desat = sqrt16( desat * 256);
+ //Serial.print("orig_desat="); Serial.print(orig_desat); Serial.println("");
+
+ // saturation is opposite of desaturation
+ s = 255 - desat;
+ //Serial.print("s.1="); Serial.print(s); Serial.println("");
+
+ if( s != 255 ) {
+ // undo 'dimming' of saturation
+ s = 255 - sqrt16( (255-s) * 256);
+ }
+ // without lib8tion: float ... ew ... sqrt... double ew, or rather, ew ^ 0.5
+ // if( s != 255 ) s = (255 - (256.0 * sqrt( (float)(255-s) / 256.0)));
+ //Serial.print("s.2="); Serial.print(s); Serial.println("");
+
+
// at least one channel is now zero
-
// if all three channels are zero, we had a
// shade of gray.
-
- uint16_t total = r + g + b;
-
- if( total == 0) {
+ if( (r + g + b) == 0) {
// we pick hue zero for no special reason
- return CHSV( 0, 0, desat);
+ return CHSV( 0, 0, 255 - s);
}
-
- // since this wasn't a pure shade of gray,
- // the interesting question is what hue is it
-
- // scale all channels up to a total of 255
- if( total != 255) {
+
+ // scale all channels up to compensate for desaturation
+ if( s < 255) {
+ if( s == 0) s = 1;
+ uint32_t scaleup = 65535 / (s);
+ r = ((uint32_t)(r) * scaleup) / 256;
+ g = ((uint32_t)(g) * scaleup) / 256;
+ b = ((uint32_t)(b) * scaleup) / 256;
+ }
+ //Serial.print("r.2="); Serial.print(r); Serial.println("");
+ //Serial.print("g.2="); Serial.print(g); Serial.println("");
+ //Serial.print("b.2="); Serial.print(b); Serial.println("");
+
+ uint16_t total = r + g + b;
+
+ //Serial.print("total="); Serial.print(total); Serial.println("");
+
+ // scale all channels up to compensate for low values
+ if( total < 255) {
+ if( total == 0) total = 1;
uint32_t scaleup = 65535 / (total);
r = ((uint32_t)(r) * scaleup) / 256;
g = ((uint32_t)(g) * scaleup) / 256;
b = ((uint32_t)(b) * scaleup) / 256;
}
-
+ //Serial.print("r.3="); Serial.print(r); Serial.println("");
+ //Serial.print("g.3="); Serial.print(g); Serial.println("");
+ //Serial.print("b.3="); Serial.print(b); Serial.println("");
+
if( total > 255 ) {
v = 255;
} else {
@@ -541,35 +587,44 @@ CHSV rgb2hsv_approximate( const CRGB& rgb)
if( v != 255) v = sqrt16( v * 256);
// without lib8tion: float ... ew ... sqrt... double ew, or rather, ew ^ 0.5
// if( v != 255) v = (256.0 * sqrt( (float)(v) / 256.0));
-
+
}
-
- // saturation is opposite of desaturation
- s = 255 - desat;
+
+ //Serial.print("v="); Serial.print(v); Serial.println("");
+
+
+#if 0
+
+ //#else
if( v != 255) {
// this part could probably use refinement/rethinking,
// (but it doesn't overflow & wrap anymore)
uint16_t s16;
s16 = (s * 256);
s16 /= v;
+ //Serial.print("s16="); Serial.print(s16); Serial.println("");
if( s16 < 256) {
s = s16;
} else {
s = 255; // clamp to prevent overflow
}
}
-
- // undo 'dimming' of saturation
- if( s != 255 ) s = 255 - sqrt16( (255-s) * 256);
- // without lib8tion: float ... ew ... sqrt... double ew, or rather, ew ^ 0.5
- // if( s != 255 ) s = (255 - (256.0 * sqrt( (float)(255-s) / 256.0)));
-
+#endif
+
+ //Serial.print("s.3="); Serial.print(s); Serial.println("");
+
+
+ // since this wasn't a pure shade of gray,
+ // the interesting question is what hue is it
+
+
+
// start with which channel is highest
// (ties don't matter)
uint8_t highest = r;
if( g > highest) highest = g;
if( b > highest) highest = b;
-
+
if( highest == r ) {
// Red is highest.
// Hue could be Purple/Pink-Red,Red-Orange,Orange-Yellow
@@ -586,14 +641,22 @@ CHSV rgb2hsv_approximate( const CRGB& rgb)
h = HUE_ORANGE;
h += scale8( qsub8((g - 85) + (171 - r), 4), FIXFRAC8(32,85)); //221
}
-
+
} else if ( highest == g) {
// Green is highest
// Hue could be Yellow-Green, Green-Aqua
if( b == 0) {
// if Blue is zero, we're in Yellow-Green
+ // G = 171..255
+ // R = 171.. 0
h = HUE_YELLOW;
- h += scale8( qadd8( qadd8((g - 128), (128 - r)), 4), FIXFRAC8(32,255)); //
+ uint8_t radj = scale8( qsub8(171,r), 47); //171..0 -> 0..171 -> 0..31
+ uint8_t gadj = scale8( qsub8(g,171), 96); //171..255 -> 0..84 -> 0..31;
+ uint8_t rgadj = radj + gadj;
+ uint8_t hueadv = rgadj / 2;
+ h += hueadv;
+ //h += scale8( qadd8( 4, qadd8((g - 128), (128 - r))),
+ // FIXFRAC8(32,255)); //
} else {
// if Blue is nonzero we're in Green-Aqua
if( (g-b) > b) {
@@ -604,7 +667,7 @@ CHSV rgb2hsv_approximate( const CRGB& rgb)
h += scale8( qsub8(b, 85), FIXFRAC8(8,42));
}
}
-
+
} else /* highest == b */ {
// Blue is highest
// Hue could be Aqua/Blue-Blue, Blue-Purple, Purple-Pink
@@ -622,9 +685,17 @@ CHSV rgb2hsv_approximate( const CRGB& rgb)
h += scale8( qsub8(r, 85), FIXFRAC8(32,85));
}
}
-
+
h += 1;
return CHSV( h, s, v);
}
+// Examples that need work:
+// 0,192,192
+// 192,64,64
+// 224,32,32
+// 252,0,126
+// 252,252,0
+// 252,252,126
+
FASTLED_NAMESPACE_END
diff --git a/hsv2rgb.h b/hsv2rgb.h
index 6611298b..ddc63baf 100644
--- a/hsv2rgb.h
+++ b/hsv2rgb.h
@@ -1,6 +1,8 @@
#ifndef __INC_HSV2RGB_H
#define __INC_HSV2RGB_H
+#include "FastLED.h"
+
#include "pixeltypes.h"
FASTLED_NAMESPACE_BEGIN
diff --git a/led_sysdefs.h b/led_sysdefs.h
index bb5fd8ff..c6cecd52 100644
--- a/led_sysdefs.h
+++ b/led_sysdefs.h
@@ -1,6 +1,8 @@
#ifndef __INC_LED_SYSDEFS_H
#define __INC_LED_SYSDEFS_H
+#include "FastLED.h"
+
#include "fastled_config.h"
#if defined(NRF51) || defined(__RFduino__)
diff --git a/lib8tion.h b/lib8tion.h
index b69a3f8c..9d66624a 100644
--- a/lib8tion.h
+++ b/lib8tion.h
@@ -1,10 +1,12 @@
+#ifndef __INC_LIB8TION_H
+#define __INC_LIB8TION_H
+
+#include "FastLED.h"
+
#ifndef __INC_LED_SYSDEFS_H
#error WTH? led_sysdefs needs to be included first
#endif
-#ifndef __INC_LIB8TION_H
-#define __INC_LIB8TION_H
-
FASTLED_NAMESPACE_BEGIN
/*
@@ -211,6 +213,8 @@ Lib8tion is pronounced like 'libation': lie-BAY-shun
#define EASE8_C 1
#define AVG8_C 1
#define AVG7_C 1
+#define AVG16_C 1
+#define AVG15_C 1
#elif defined(__AVR__)
@@ -225,6 +229,8 @@ Lib8tion is pronounced like 'libation': lie-BAY-shun
#define SUB8_C 0
#define AVG8_C 0
#define AVG7_C 0
+#define AVG16_C 0
+#define AVG15_C 0
#define QADD8_AVRASM 1
#define QADD7_AVRASM 1
@@ -234,6 +240,8 @@ Lib8tion is pronounced like 'libation': lie-BAY-shun
#define SUB8_AVRASM 1
#define AVG8_AVRASM 1
#define AVG7_AVRASM 1
+#define AVG16_AVRASM 1
+#define AVG15_AVRASM 1
// Note: these require hardware MUL instruction
// -- sorry, ATtiny!
@@ -285,6 +293,8 @@ Lib8tion is pronounced like 'libation': lie-BAY-shun
#define EASE8_C 1
#define AVG8_C 1
#define AVG7_C 1
+#define AVG16_C 1
+#define AVG15_C 1
#endif
diff --git a/lib8tion/math8.h b/lib8tion/math8.h
index 9e87adc4..f41352a9 100644
--- a/lib8tion/math8.h
+++ b/lib8tion/math8.h
@@ -163,6 +163,31 @@ LIB8STATIC uint8_t avg8( uint8_t i, uint8_t j)
#endif
}
+/// Calculate an integer average of two unsigned
+/// 16-bit integer values (uint16_t).
+/// Fractional results are rounded down, e.g. avg16(20,41) = 30
+LIB8STATIC uint16_t avg16( uint16_t i, uint16_t j)
+{
+#if AVG16_C == 1
+ return (uint32_t)((uint32_t)(i) + (uint32_t)(j)) >> 1;
+#elif AVG16_AVRASM == 1
+ asm volatile(
+ /* First, add jLo (heh) to iLo, 9th bit overflows into C flag */
+ "add %A[i], %A[j] \n\t"
+ /* Now, add C + jHi to iHi, 17th bit overflows into C flag */
+ "adc %B[i], %B[j] \n\t"
+ /* Divide iHi by two, moving C flag into high 16th bit, old 9th bit now in C */
+ "ror %B[i] \n\t"
+ /* Divide iLo by two, moving C flag into high 8th bit */
+ "ror %A[i] \n\t"
+ : [i] "+a" (i)
+ : [j] "a" (j) );
+ return i;
+#else
+#error "No implementation for avg16 available."
+#endif
+}
+
/// Calculate an integer average of two signed 7-bit
/// integers (int8_t)
@@ -185,6 +210,34 @@ LIB8STATIC int8_t avg7( int8_t i, int8_t j)
#endif
}
+/// Calculate an integer average of two signed 15-bit
+/// integers (int16_t)
+/// If the first argument is even, result is rounded down.
+/// If the first argument is odd, result is result up.
+LIB8STATIC int16_t avg15( int16_t i, int16_t j)
+{
+#if AVG15_C == 1
+ return ((int32_t)((int32_t)(i) + (int32_t)(j)) >> 1) + (i & 0x1);
+#elif AVG15_AVRASM == 1
+ asm volatile(
+ /* first divide j by 2, throwing away lowest bit */
+ "asr %B[j] \n\t"
+ "ror %A[j] \n\t"
+ /* now divide i by 2, with lowest bit going into C */
+ "asr %B[i] \n\t"
+ "ror %A[i] \n\t"
+ /* add j + C to i */
+ "adc %A[i], %A[j] \n\t"
+ "adc %B[i], %B[j] \n\t"
+ : [i] "+a" (i)
+ : [j] "a" (j) );
+ return i;
+#else
+#error "No implementation for avg15 available."
+#endif
+}
+
+
/// Calculate the remainder of one unsigned 8-bit
/// value divided by anoter, aka A % M.
/// Implemented by repeated subtraction, which is
diff --git a/lib8tion/scale8.h b/lib8tion/scale8.h
index 239e9dea..e6bdeefd 100644
--- a/lib8tion/scale8.h
+++ b/lib8tion/scale8.h
@@ -388,8 +388,7 @@ LIB8STATIC uint16_t scale16( uint16_t i, fract16 scale )
result = ((uint32_t)(i) * (uint32_t)(scale)) / 65536;
return result;
#elif SCALE16_AVRASM == 1
- uint32_t result = 0;
- const uint8_t zero = 0;
+ uint32_t result;
asm volatile(
// result.A-B = i.A x scale.A
" mul %A[i], %A[scale] \n\t"
@@ -406,12 +405,26 @@ LIB8STATIC uint16_t scale16( uint16_t i, fract16 scale )
// well, in case we want to use this code for
// a generic 16x16 multiply somewhere.
+ : [result] "=r" (result)
+ : [i] "r" (i),
+ [scale] "r" (scale)
+ : "r0", "r1"
+ );
+
+ asm volatile(
// result.C-D = i.B x scale.B
" mul %B[i], %B[scale] \n\t"
//" mov %C[result], r0 \n\t"
//" mov %D[result], r1 \n\t"
" movw %C[result], r0 \n\t"
+ : [result] "+r" (result)
+ : [i] "r" (i),
+ [scale] "r" (scale)
+ : "r0", "r1"
+ );
+ const uint8_t zero = 0;
+ asm volatile(
// result.B-D += i.B x scale.A
" mul %B[i], %A[scale] \n\t"
@@ -435,6 +448,7 @@ LIB8STATIC uint16_t scale16( uint16_t i, fract16 scale )
[zero] "r" (zero)
: "r0", "r1"
);
+
result = result >> 16;
return result;
#else
diff --git a/library.properties b/library.properties
index f5093f33..db96f3c9 100644
--- a/library.properties
+++ b/library.properties
@@ -1,5 +1,5 @@
name=FastLED
-version=3.1.0
+version=3.1.1
author=Daniel Garcia
maintainer=Daniel Garcia <dgarcia@fastled.io>
sentence=Multi-platform library for controlling dozens of different types of LEDs along with optimized math, effect, and noise functions.
diff --git a/noise.cpp b/noise.cpp
index 190e74e7..8b1f6a4d 100644
--- a/noise.cpp
+++ b/noise.cpp
@@ -20,6 +20,37 @@ FL_PROGMEM static uint8_t const p[] = { 151,160,137,91,90,15,
138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180,151
};
+
+#if FASTLED_NOISE_ALLOW_AVERAGE_TO_OVERFLOW == 1
+#define AVG15(U,V) (((U)+(V)) >> 1)
+#else
+// See if we should use the inlined avg15 for AVR with MUL instruction
+#if defined(__AVR__) && (LIB8_ATTINY == 0)
+#define AVG15(U,V) (avg15_inline_avr_mul((U),(V)))
+// inlined copy of avg15 for AVR with MUL instruction; cloned from math8.h
+// Forcing this inline in the 3-D 16bit noise produces a 12% speedup overall,
+// at a cost of just +8 bytes of net code size.
+static int16_t inline __attribute__((always_inline)) avg15_inline_avr_mul( int16_t i, int16_t j)
+{
+ asm volatile(
+ /* first divide j by 2, throwing away lowest bit */
+ "asr %B[j] \n\t"
+ "ror %A[j] \n\t"
+ /* now divide i by 2, with lowest bit going into C */
+ "asr %B[i] \n\t"
+ "ror %A[i] \n\t"
+ /* add j + C to i */
+ "adc %A[i], %A[j] \n\t"
+ "adc %B[i], %B[j] \n\t"
+ : [i] "+a" (i)
+ : [j] "a" (j) );
+ return i;
+}
+#else
+#define AVG15(U,V) (avg15((U),(V)))
+#endif
+#endif
+
//
// #define FADE_12
#define FADE_16
@@ -58,7 +89,7 @@ static int16_t inline __attribute__((always_inline)) grad16(uint8_t hash, int16
if(hash&1) { u = -u; }
if(hash&2) { v = -v; }
- return (u+v)>>1;
+ return AVG15(u,v);
#endif
}
@@ -69,7 +100,7 @@ static int16_t inline __attribute__((always_inline)) grad16(uint8_t hash, int16_
if(hash&1) { u = -u; }
if(hash&2) { v = -v; }
- return (u+v)>>1;
+ return AVG15(u,v);
}
static int16_t inline __attribute__((always_inline)) grad16(uint8_t hash, int16_t x) {
@@ -81,7 +112,7 @@ static int16_t inline __attribute__((always_inline)) grad16(uint8_t hash, int16_
if(hash&1) { u = -u; }
if(hash&2) { v = -v; }
- return (u+v)>>1;
+ return AVG15(u,v);
}
// selectBasedOnHashBit performs this:
@@ -290,7 +321,13 @@ uint16_t inoise16(uint32_t x, uint32_t y, uint32_t z) {
int32_t ans = inoise16_raw(x,y,z);
ans = ans + 19052L;
uint32_t pan = ans;
- return (pan*220L)>>7;
+ // pan = (ans * 220L) >> 7. That's the same as:
+ // pan = (ans * 440L) >> 8. And this way avoids a 7X four-byte shift-loop on AVR.
+ // Identical math, except for the highest bit, which we don't care about anyway,
+ // since we're returning the 'middle' 16 out of a 32-bit value anyway.
+ pan *= 440L;
+ return (pan>>8);
+
// // return scale16by8(pan,220)<<1;
// return ((inoise16_raw(x,y,z)+19052)*220)>>7;
// return scale16by8(inoise16_raw(x,y,z)+19052,220)<<1;
@@ -333,7 +370,13 @@ uint16_t inoise16(uint32_t x, uint32_t y) {
int32_t ans = inoise16_raw(x,y);
ans = ans + 17308L;
uint32_t pan = ans;
- return (pan*242L)>>7;
+ // pan = (ans * 242L) >> 7. That's the same as:
+ // pan = (ans * 484L) >> 8. And this way avoids a 7X four-byte shift-loop on AVR.
+ // Identical math, except for the highest bit, which we don't care about anyway,
+ // since we're returning the 'middle' 16 out of a 32-bit value anyway.
+ pan *= 484L;
+ return (pan>>8);
+
// return (uint32_t)(((int32_t)inoise16_raw(x,y)+(uint32_t)17308)*242)>>7;
// return scale16by8(inoise16_raw(x,y)+17308,242)<<1;
}
@@ -655,7 +698,7 @@ void fill_noise8(CRGB *leds, int num_leds,
void fill_noise16(CRGB *leds, int num_leds,
uint8_t octaves, uint16_t x, int scale,
uint8_t hue_octaves, uint16_t hue_x, int hue_scale,
- uint16_t time) {
+ uint16_t time, uint8_t hue_shift) {
uint8_t V[num_leds];
uint8_t H[num_leds];
@@ -666,7 +709,7 @@ void fill_noise16(CRGB *leds, int num_leds,
fill_raw_noise8(H,num_leds,hue_octaves,hue_x,hue_scale,time);
for(int i = 0; i < num_leds; i++) {
- leds[i] = CHSV(H[i],255,V[i]);
+ leds[i] = CHSV(H[i] + hue_shift,255,V[i]);
}
}
diff --git a/noise.h b/noise.h
index b968815a..7355e23e 100644
--- a/noise.h
+++ b/noise.h
@@ -1,6 +1,8 @@
#ifndef __INC_NOISE_H
#define __INC_NOISE_H
+#include "FastLED.h"
+
FASTLED_NAMESPACE_BEGIN
///@file noise.h
@@ -81,7 +83,7 @@ void fill_noise8(CRGB *leds, int num_leds,
void fill_noise16(CRGB *leds, int num_leds,
uint8_t octaves, uint16_t x, int scale,
uint8_t hue_octaves, uint16_t hue_x, int hue_scale,
- uint16_t time);
+ uint16_t time, uint8_t hue_shift=0);
void fill_2dnoise8(CRGB *leds, int width, int height, bool serpentine,
uint8_t octaves, uint16_t x, int xscale, uint16_t y, int yscale, uint16_t time,
uint8_t hue_octaves, uint16_t hue_x, int hue_xscale, uint16_t hue_y, uint16_t hue_yscale,uint16_t hue_time,bool blend);
diff --git a/pixelset.h b/pixelset.h
new file mode 100644
index 00000000..345b6071
--- /dev/null
+++ b/pixelset.h
@@ -0,0 +1,300 @@
+#ifndef __INC_PIXELSET_H
+#define __INC_PIXELSET_H
+
+#include "FastLED.h"
+
+/// Represents a set of CRGB led objects. Provides the [] array operator, and works like a normal array in that case.
+/// This should be kept in sync with the set of functions provided by CRGB as well as functions in colorutils. Note
+/// that a pixel set is a window into another set of led data, it is not its own set of led data.
+template<class PIXEL_TYPE>
+class CPixelView {
+public:
+ const int8_t dir;
+ const int len;
+ PIXEL_TYPE * const leds;
+ PIXEL_TYPE * const end_pos;
+
+public:
+
+ /// PixelSet copy constructor
+ inline CPixelView(const CPixelView & other) : dir(other.dir), len(other.len), leds(other.leds), end_pos(other.end_pos) {}
+
+ /// pixelset constructor for a pixel set starting at the given PIXEL_TYPE* and going for _len leds. Note that the length
+ /// can be backwards, creating a PixelSet that walks backwards over the data
+ /// @param leds point to the raw led data
+ /// @param len how many leds in this set
+ inline CPixelView(PIXEL_TYPE *_leds, int _len) : dir(_len < 0 ? -1 : 1), len(_len), leds(_leds), end_pos(_leds + _len) {}
+
+ /// PixelSet constructor for the given set of leds, with start and end boundaries. Note that start can be after
+ /// end, resulting in a set that will iterate backwards
+ /// @param leds point to the raw led data
+ /// @param start the start index of the leds for this array
+ /// @param end the end index of the leds for this array
+ inline CPixelView(PIXEL_TYPE *_leds, int _start, int _end) : dir(((_end-_start)<0) ? -1 : 1), len((_end - _start) + dir), leds(_leds + _start), end_pos(_leds + _start + len) {}
+
+ /// Get the size of this set
+ /// @return the size of the set
+ int size() { return abs(len); }
+
+ /// Whether or not this set goes backwards
+ /// @return whether or not the set is backwards
+ bool reversed() { return len < 0; }
+
+ /// do these sets point to the same thing (note, this is different from the contents of the set being the same)
+ bool operator==(const CPixelView & rhs) const { return leds == rhs.leds && len == rhs.len && dir == rhs.dir; }
+
+ /// do these sets point to the different things (note, this is different from the contents of the set being the same)
+ bool operator!=(const CPixelView & rhs) const { return leds != rhs.leds || len != rhs.len || dir != rhs.dir; }
+
+ /// access a single element in this set, just like an array operator
+ inline PIXEL_TYPE & operator[](int x) const { if(dir & 0x80) { return leds[-x]; } else { return leds[x]; } }
+
+ /// Access an inclusive subset of the leds in this set. Note that start can be greater than end, which will
+ /// result in a reverse ordering for many functions (useful for mirroring)
+ /// @param start the first element from this set for the new subset
+ /// @param end the last element for the new subset
+ inline CPixelView operator()(int start, int end) { return CPixelView(leds, start, end); }
+
+ /// Access an inclusive subset of the leds in this set, starting from the first.
+ /// @param end the last element for the new subset
+ /// Not sure i want this? inline CPixelView operator()(int end) { return CPixelView(leds, 0, end); }
+
+ /// Return the reverse ordering of this set
+ inline CPixelView operator-() { return CPixelView(leds + len - dir, len - dir, 0); }
+
+ /// Return a pointer to the first element in this set
+ inline operator PIXEL_TYPE* () const { return leds; }
+
+ /// Assign the passed in color to all elements in this set
+ /// @param color the new color for the elements in the set
+ inline CPixelView & operator=(const PIXEL_TYPE & color) {
+ for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel) = color; }
+ return *this;
+ }
+
+
+ void dump() const {
+/**
+ Serial.print("len: "); Serial.print(len); Serial.print(", dir:"); Serial.print((int)dir);
+ Serial.print(", range:"); Serial.print((uint32_t)leds); Serial.print("-"); Serial.print((uint32_t)end_pos);
+ Serial.print(", diff:"); Serial.print((int32_t)(end_pos - leds));
+ Serial.println("");
+ **/
+ }
+
+ /// Copy the contents of the passed in set to our set. Note if one set is smaller than the other, only the
+ /// smallest number of items will be copied over.
+ inline CPixelView & operator=(const CPixelView & rhs) {
+ for(iterator pixel = begin(), rhspixel = rhs.begin(), _end = end(), rhs_end = rhs.end(); (pixel != _end) && (rhspixel != rhs_end); ++pixel, ++rhspixel) {
+ (*pixel) = (*rhspixel);
+ }
+ return *this;
+ }
+
+ /// @name modification/scaling operators
+ //@{
+ /// Add the passed in value to r,g, b for all the pixels in this set
+ inline CPixelView & addToRGB(uint8_t inc) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel) += inc; } return *this; }
+ /// Add every pixel in the other set to this set
+ inline CPixelView & operator+=(CPixelView & rhs) { for(iterator pixel = begin(), rhspixel = rhs.begin(), _end = end(), rhs_end = rhs.end(); (pixel != _end) && (rhspixel != rhs_end); ++pixel, ++rhspixel) { (*pixel) += (*rhspixel); } return *this; }
+
+ /// Subtract the passed in value from r,g,b for all pixels in this set
+ inline CPixelView & subFromRGB(uint8_t inc) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel) -= inc; } return *this; }
+ /// Subtract every pixel in the other set from this set
+ inline CPixelView & operator-=(CPixelView & rhs) { for(iterator pixel = begin(), rhspixel = rhs.begin(), _end = end(), rhs_end = rhs.end(); (pixel != _end) && (rhspixel != rhs_end); ++pixel, ++rhspixel) { (*pixel) -= (*rhspixel); } return *this; }
+
+ /// Increment every pixel value in this set
+ inline CPixelView & operator++() { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel)++; } return *this; }
+ /// Increment every pixel value in this set
+ inline CPixelView & operator++(int DUMMY_ARG) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel)++; } return *this; }
+
+ /// Decrement every pixel value in this set
+ inline CPixelView & operator--() { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel)--; } return *this; }
+ /// Decrement every pixel value in this set
+ inline CPixelView & operator--(int DUMMY_ARG) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel)--; } return *this; }
+
+ /// Divide every led by the given value
+ inline CPixelView & operator/=(uint8_t d) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel) /= d; } return *this; }
+ /// Shift every led in this set right by the given number of bits
+ inline CPixelView & operator>>=(uint8_t d) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel) >>= d; } return *this; }
+ /// Multiply every led in this set by the given value
+ inline CPixelView & operator*=(uint8_t d) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel) *= d; } return *this; }
+
+ /// Scale every led by the given scale
+ inline CPixelView & nscale8_video(uint8_t scaledown) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel).nscale8_video(scaledown); } return *this;}
+ /// Scale down every led by the given scale
+ inline CPixelView & operator%=(uint8_t scaledown) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel).nscale8_video(scaledown); } return *this; }
+ /// Fade every led down by the given scale
+ inline CPixelView & fadeLightBy(uint8_t fadefactor) { return nscale8_video(255 - fadefactor); }
+
+ /// Scale every led by the given scale
+ inline CPixelView & nscale8(uint8_t scaledown) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel).nscale8(scaledown); } return *this; }
+ /// Scale every led by the given scale
+ inline CPixelView & nscale8(PIXEL_TYPE & scaledown) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel).nscale8(scaledown); } return *this; }
+ /// Scale every led in this set by every led in the other set
+ inline CPixelView & nscale8(CPixelView & rhs) { for(iterator pixel = begin(), rhspixel = rhs.begin(), _end = end(), rhs_end = rhs.end(); (pixel != _end) && (rhspixel != rhs_end); ++pixel, ++rhspixel) { (*pixel).nscale8((*rhspixel)); } return *this; }
+
+ /// Fade every led down by the given scale
+ inline CPixelView & fadeToBlackBy(uint8_t fade) { return nscale8(255 - fade); }
+
+ /// Apply the PIXEL_TYPE |= operator to every pixel in this set with the given PIXEL_TYPE value (bringing each channel to the higher of the two values)
+ inline CPixelView & operator|=(const PIXEL_TYPE & rhs) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel) |= rhs; } return *this; }
+ /// Apply the PIXEL_TYPE |= operator to every pixel in this set with every pixel in the passed in set
+ inline CPixelView & operator|=(const CPixelView & rhs) { for(iterator pixel = begin(), rhspixel = rhs.begin(), _end = end(), rhs_end = rhs.end(); (pixel != _end) && (rhspixel != rhs_end); ++pixel, ++rhspixel) { (*pixel) |= (*rhspixel); } return *this; }
+ /// Apply the PIXEL_TYPE |= operator to every pixel in this set
+ inline CPixelView & operator|=(uint8_t d) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel) |= d; } return *this; }
+
+ /// Apply the PIXEL_TYPE &= operator to every pixel in this set with the given PIXEL_TYPE value (bringing each channel down to the lower of the two values)
+ inline CPixelView & operator&=(const PIXEL_TYPE & rhs) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel) &= rhs; } return *this; }
+ /// Apply the PIXEL_TYPE &= operator to every pixel in this set with every pixel in the passed in set
+ inline CPixelView & operator&=(const CPixelView & rhs) { for(iterator pixel = begin(), rhspixel = rhs.begin(), _end = end(), rhs_end = rhs.end(); (pixel != _end) && (rhspixel != rhs_end); ++pixel, ++rhspixel) { (*pixel) &= (*rhspixel); } return *this; }
+ /// APply the PIXEL_TYPE &= operator to every pixel in this set with the passed in value
+ inline CPixelView & operator&=(uint8_t d) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel) &= d; } return *this; }
+ //@}
+
+ /// Returns whether or not any leds in this set are non-zero
+ inline operator bool() { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { if((*pixel)) return true; } return false; }
+
+ // Color util functions
+ inline CPixelView & fill_solid(const PIXEL_TYPE & color) { *this = color; return *this; }
+ inline CPixelView & fill_solid(const CHSV & color) { if(dir>0) { *this = color; return *this; } }
+
+ inline CPixelView & fill_rainbow(uint8_t initialhue, uint8_t deltahue=5) {
+ if(dir >= 0) {
+ ::fill_rainbow(leds,len,initialhue,deltahue);
+ } else {
+ ::fill_rainbow(leds+len+1,-len,initialhue,deltahue);
+ }
+ return *this;
+ }
+
+ inline CPixelView & fill_gradient(const CHSV & startcolor, const CHSV & endcolor, TGradientDirectionCode directionCode = SHORTEST_HUES) {
+ if(dir >= 0) {
+ ::fill_gradient(leds,len,startcolor, endcolor, directionCode);
+ } else {
+ ::fill_gradient(leds + len + 1, (-len), endcolor, startcolor, directionCode);
+ }
+ return *this;
+ }
+
+ inline CPixelView & fill_gradient(const CHSV & c1, const CHSV & c2, const CHSV & c3, TGradientDirectionCode directionCode = SHORTEST_HUES) {
+ if(dir >= 0) {
+ ::fill_gradient(leds, len, c1, c2, c3, directionCode);
+ } else {
+ ::fill_gradient(leds + len + 1, -len, c3, c2, c1, directionCode);
+ }
+ return *this;
+ }
+
+ inline CPixelView & fill_gradient(const CHSV & c1, const CHSV & c2, const CHSV & c3, const CHSV & c4, TGradientDirectionCode directionCode = SHORTEST_HUES) {
+ if(dir >= 0) {
+ ::fill_gradient(leds, len, c1, c2, c3, c4, directionCode);
+ } else {
+ ::fill_gradient(leds + len + 1, -len, c4, c3, c2, c1, directionCode);
+ }
+ return *this;
+ }
+
+ inline CPixelView & fill_gradient_RGB(const PIXEL_TYPE & startcolor, const PIXEL_TYPE & endcolor, TGradientDirectionCode directionCode = SHORTEST_HUES) {
+ if(dir >= 0) {
+ ::fill_gradient_RGB(leds,len,startcolor, endcolor);
+ } else {
+ ::fill_gradient_RGB(leds + len + 1, (-len), endcolor, startcolor);
+ }
+ return *this;
+ }
+
+ inline CPixelView & fill_gradient_RGB(const PIXEL_TYPE & c1, const PIXEL_TYPE & c2, const PIXEL_TYPE & c3) {
+ if(dir >= 0) {
+ ::fill_gradient_RGB(leds, len, c1, c2, c3);
+ } else {
+ ::fill_gradient_RGB(leds + len + 1, -len, c3, c2, c1);
+ }
+ return *this;
+ }
+
+ inline CPixelView & fill_gradient_RGB(const PIXEL_TYPE & c1, const PIXEL_TYPE & c2, const PIXEL_TYPE & c3, const PIXEL_TYPE & c4) {
+ if(dir >= 0) {
+ ::fill_gradient_RGB(leds, len, c1, c2, c3, c4);
+ } else {
+ ::fill_gradient_RGB(leds + len + 1, -len, c4, c3, c2, c1);
+ }
+ return *this;
+ }
+
+ inline CPixelView & nblend(const PIXEL_TYPE & overlay, fract8 amountOfOverlay) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { ::nblend((*pixel), overlay, amountOfOverlay); } return *this; }
+ inline CPixelView & nblend(const CPixelView & rhs, fract8 amountOfOverlay) { for(iterator pixel = begin(), rhspixel = rhs.begin(), _end = end(), rhs_end = rhs.end(); (pixel != _end) && (rhspixel != rhs_end); ++pixel, ++rhspixel) { ::nblend((*pixel), (*rhspixel), amountOfOverlay); } return *this; }
+
+ // Note: only bringing in a 1d blur, not sure 2d blur makes sense when looking at sub arrays
+ inline CPixelView & blur1d(fract8 blur_amount) {
+ if(dir >= 0) {
+ ::blur1d(leds, len, blur_amount);
+ } else {
+ ::blur1d(leds + len + 1, -len, blur_amount);
+ }
+ return *this;
+ }
+
+ inline CPixelView & napplyGamma_video(float gamma) {
+ if(dir >= 0) {
+ ::napplyGamma_video(leds, len, gamma);
+ } else {
+ ::napplyGamma_video(leds + len + 1, -len, gamma);
+ }
+ return *this;
+ }
+
+ inline CPixelView & napplyGamma_video(float gammaR, float gammaG, float gammaB) {
+ if(dir >= 0) {
+ ::napplyGamma_video(leds, len, gammaR, gammaG, gammaB);
+ } else {
+ ::napplyGamma_video(leds + len + 1, -len, gammaR, gammaG, gammaB);
+ }
+ return *this;
+ }
+
+ // TODO: Make this a fully specified/proper iterator
+ template <class T>
+ class pixelset_iterator_base {
+ T * leds;
+ const int8_t dir;
+ public:
+ __attribute__((always_inline)) inline pixelset_iterator_base(const pixelset_iterator_base & rhs) : leds(rhs.leds), dir(rhs.dir) {}
+ __attribute__((always_inline)) inline pixelset_iterator_base(T * _leds, const char _dir) : leds(_leds), dir(_dir) {}
+
+ __attribute__((always_inline)) inline pixelset_iterator_base& operator++() { leds += dir; return *this; }
+ __attribute__((always_inline)) inline pixelset_iterator_base operator++(int) { pixelset_iterator_base tmp(*this); leds += dir; return tmp; }
+
+ __attribute__((always_inline)) inline bool operator==(pixelset_iterator_base & other) const { return leds == other.leds; } // && set==other.set; }
+ __attribute__((always_inline)) inline bool operator!=(pixelset_iterator_base & other) const { return leds != other.leds; } // || set != other.set; }
+
+ __attribute__((always_inline)) inline PIXEL_TYPE& operator*() const { return *leds; }
+ };
+
+ typedef pixelset_iterator_base<PIXEL_TYPE> iterator;
+ typedef pixelset_iterator_base<const PIXEL_TYPE> const_iterator;
+
+ iterator begin() { return iterator(leds, dir); }
+ iterator end() { return iterator(end_pos, dir); }
+
+ iterator begin() const { return iterator(leds, dir); }
+ iterator end() const { return iterator(end_pos, dir); }
+
+ const_iterator cbegin() const { return const_iterator(leds, dir); }
+ const_iterator cend() const { return const_iterator(end_pos, dir); }
+};
+
+typedef CPixelView<CRGB> CRGBSet;
+
+__attribute__((always_inline))
+inline CRGB *operator+(const CRGBSet & pixels, int offset) { return (CRGB*)pixels + offset; }
+
+
+template<int SIZE>
+class CRGBArray : public CPixelView<CRGB> {
+ CRGB rawleds[SIZE];
+public:
+ CRGBArray() : CPixelView<CRGB>(rawleds, SIZE) {}
+};
+
+#endif
diff --git a/pixeltypes.h b/pixeltypes.h
index 8ff9120b..89225ae1 100644
--- a/pixeltypes.h
+++ b/pixeltypes.h
@@ -1,6 +1,8 @@
#ifndef __INC_PIXELS_H
#define __INC_PIXELS_H
+#include "FastLED.h"
+
#include <stdint.h>
#include "lib8tion.h"
#include "color.h"
diff --git a/platforms.h b/platforms.h
index 4f5d7ee6..c36b016c 100644
--- a/platforms.h
+++ b/platforms.h
@@ -1,6 +1,8 @@
#ifndef __INC_PLATFORMS_H
#define __INC_PLATFORMS_H
+#include "FastLED.h"
+
#include "fastled_config.h"
#if defined(NRF51)
diff --git a/platforms/avr/fastpin_avr.h b/platforms/avr/fastpin_avr.h
index a4cff31c..69a01a14 100644
--- a/platforms/avr/fastpin_avr.h
+++ b/platforms/avr/fastpin_avr.h
@@ -30,9 +30,9 @@ public:
inline static void toggle() __attribute__ ((always_inline)) { _PIN::r() = _MASK; }
- inline static void hi(register port_ptr_t port) __attribute__ ((always_inline)) { hi(); }
- inline static void lo(register port_ptr_t port) __attribute__ ((always_inline)) { lo(); }
- inline static void fastset(register port_ptr_t port, register uint8_t val) __attribute__ ((always_inline)) { set(val); }
+ inline static void hi(register port_ptr_t /*port*/) __attribute__ ((always_inline)) { hi(); }
+ inline static void lo(register port_ptr_t /*port*/) __attribute__ ((always_inline)) { lo(); }
+ inline static void fastset(register port_ptr_t /*port*/, register uint8_t val) __attribute__ ((always_inline)) { set(val); }
inline static port_t hival() __attribute__ ((always_inline)) { return _PORT::r() | _MASK; }
inline static port_t loval() __attribute__ ((always_inline)) { return _PORT::r() & ~_MASK; }
@@ -141,25 +141,50 @@ _DEFPIN_AVR(16, 0x04, C); _DEFPIN_AVR(17, 0x08, C); _DEFPIN_AVR(18, 0x10, C); _D
#define AVR_HARDWARE_SPI 1
#define HAS_HARDWARE_PIN_SUPPORT 1
+#ifndef __AVR_ATmega8__
#define SPI_UART0_DATA 1
#define SPI_UART0_CLOCK 4
+#endif
#elif defined(__AVR_ATmega1284P__)
_IO(A); _IO(B); _IO(C); _IO(D);
-_DEFPIN_AVR(0, 1<<0, D); _DEFPIN_AVR(1, 1<<1, D); _DEFPIN_AVR(2, 1<<2, B); _DEFPIN_AVR(3, 1<<3, B);
-_DEFPIN_AVR(4, 1<<0, B); _DEFPIN_AVR(5, 1<<1, B); _DEFPIN_AVR(6, 1<<2, D); _DEFPIN_AVR(7, 1<<3, D);
-_DEFPIN_AVR(8, 1<<5, D); _DEFPIN_AVR(9, 1<<6, D); _DEFPIN_AVR(10, 1<<4, B); _DEFPIN_AVR(11, 1<<5, B);
-_DEFPIN_AVR(12, 1<<6, B); _DEFPIN_AVR(13, 1<<7, B); _DEFPIN_AVR(14, 1<<7, A); _DEFPIN_AVR(15, 1<<6, A);
-_DEFPIN_AVR(16, 1<<5, A); _DEFPIN_AVR(17, 1<<4, A); _DEFPIN_AVR(18, 1<<3, A); _DEFPIN_AVR(19, 1<<2, A);
-_DEFPIN_AVR(20, 1<<1, A); _DEFPIN_AVR(21, 1<<0, A); _DEFPIN_AVR(22, 1<<0, C); _DEFPIN_AVR(23, 1<<1, C);
-_DEFPIN_AVR(24, 1<<2, C); _DEFPIN_AVR(25, 1<<3, C); _DEFPIN_AVR(26, 1<<4, C); _DEFPIN_AVR(27, 1<<5, C);
-_DEFPIN_AVR(28, 1<<6, C); _DEFPIN_AVR(29, 1<<7, C); _DEFPIN_AVR(30, 1<<4, D); _DEFPIN_AVR(31, 1<<7, D);
+#define MAX_PIN 31
+_DEFPIN_AVR(0, 1<<0, B); _DEFPIN_AVR(1, 1<<1, B); _DEFPIN_AVR(2, 1<<2, B); _DEFPIN_AVR(3, 1<<3, B);
+_DEFPIN_AVR(4, 1<<4, B); _DEFPIN_AVR(5, 1<<5, B); _DEFPIN_AVR(6, 1<<6, B); _DEFPIN_AVR(7, 1<<7, B);
+_DEFPIN_AVR(8, 1<<0, D); _DEFPIN_AVR(9, 1<<1, D); _DEFPIN_AVR(10, 1<<2, D); _DEFPIN_AVR(11, 1<<3, D);
+_DEFPIN_AVR(12, 1<<4, D); _DEFPIN_AVR(13, 1<<5, D); _DEFPIN_AVR(14, 1<<6, D); _DEFPIN_AVR(15, 1<<7, D);
+_DEFPIN_AVR(16, 1<<0, C); _DEFPIN_AVR(17, 1<<1, C); _DEFPIN_AVR(18, 1<<2, C); _DEFPIN_AVR(19, 1<<3, C);
+_DEFPIN_AVR(20, 1<<4, C); _DEFPIN_AVR(21, 1<<5, C); _DEFPIN_AVR(22, 1<<6, C); _DEFPIN_AVR(23, 1<<7, C);
+_DEFPIN_AVR(24, 1<<0, A); _DEFPIN_AVR(25, 1<<1, A); _DEFPIN_AVR(26, 1<<2, A); _DEFPIN_AVR(27, 1<<3, A);
+_DEFPIN_AVR(28, 1<<4, A); _DEFPIN_AVR(29, 1<<5, A); _DEFPIN_AVR(30, 1<<6, A); _DEFPIN_AVR(31, 1<<7, A);
+
+#define SPI_DATA 5
+#define SPI_CLOCK 7
+#define SPI_SELECT 4
+#define AVR_HARDWARE_SPI 1
+#define HAS_HARDWARE_PIN_SUPPORT 1
+
+#elif defined(__AVR_ATmega128RFA1__) || defined(__AVR_ATmega256RFR2__)
+
+// AKA the Pinoccio
+
+_IO(A); _IO(B); _IO(C); _IO(D); _IO(E); _IO(F);
+
+_DEFPIN_AVR( 0, 1<<0, E); _DEFPIN_AVR( 1, 1<<1, E); _DEFPIN_AVR( 2, 1<<7, B); _DEFPIN_AVR( 3, 1<<3, E);
+_DEFPIN_AVR( 4, 1<<4, E); _DEFPIN_AVR( 5, 1<<5, E); _DEFPIN_AVR( 6, 1<<2, E); _DEFPIN_AVR( 7, 1<<6, E);
+_DEFPIN_AVR( 8, 1<<5, D); _DEFPIN_AVR( 9, 1<<0, B); _DEFPIN_AVR(10, 1<<2, B); _DEFPIN_AVR(11, 1<<3, B);
+_DEFPIN_AVR(12, 1<<1, B); _DEFPIN_AVR(13, 1<<2, D); _DEFPIN_AVR(14, 1<<3, D); _DEFPIN_AVR(15, 1<<0, D);
+_DEFPIN_AVR(16, 1<<1, D); _DEFPIN_AVR(17, 1<<4, D); _DEFPIN_AVR(18, 1<<7, E); _DEFPIN_AVR(19, 1<<6, D);
+_DEFPIN_AVR(20, 1<<7, D); _DEFPIN_AVR(21, 1<<4, B); _DEFPIN_AVR(22, 1<<5, B); _DEFPIN_AVR(23, 1<<6, B);
+_DEFPIN_AVR(24, 1<<0, F); _DEFPIN_AVR(25, 1<<1, F); _DEFPIN_AVR(26, 1<<2, F); _DEFPIN_AVR(27, 1<<3, F);
+_DEFPIN_AVR(28, 1<<4, F); _DEFPIN_AVR(29, 1<<5, F); _DEFPIN_AVR(30, 1<<6, F); _DEFPIN_AVR(31, 1<<7, F);
+
+#define SPI_DATA 10
+#define SPI_CLOCK 12
+#define SPI_SELECT 9
-#define SPI_DATA 11
-#define SPI_CLOCK 13
-#define SPI_SELECT 10
#define AVR_HARDWARE_SPI 1
#define HAS_HARDWARE_PIN_SUPPORT 1
@@ -253,14 +278,15 @@ _DEFPIN_AVR(44, 64, F); _DEFPIN_AVR(45, 128, F);
// leonard defs
_IO(B); _IO(C); _IO(D); _IO(E); _IO(F);
-#define MAX_PIN 24
+#define MAX_PIN 30
_DEFPIN_AVR(0, 4, D); _DEFPIN_AVR(1, 8, D); _DEFPIN_AVR(2, 2, D); _DEFPIN_AVR(3, 1, D);
_DEFPIN_AVR(4, 16, D); _DEFPIN_AVR(5, 64, C); _DEFPIN_AVR(6, 128, D); _DEFPIN_AVR(7, 64, E);
_DEFPIN_AVR(8, 16, B); _DEFPIN_AVR(9, 32, B); _DEFPIN_AVR(10, 64, B); _DEFPIN_AVR(11, 128, B);
_DEFPIN_AVR(12, 64, D); _DEFPIN_AVR(13, 128, C); _DEFPIN_AVR(14, 8, B); _DEFPIN_AVR(15, 2, B);
_DEFPIN_AVR(16, 4, B); _DEFPIN_AVR(17, 1, B); _DEFPIN_AVR(18, 128, F); _DEFPIN_AVR(19, 64, F);
_DEFPIN_AVR(20, 32, F); _DEFPIN_AVR(21, 16, F); _DEFPIN_AVR(22, 2, F); _DEFPIN_AVR(23, 1, F);
- _DEFPIN_AVR(24, 32, D);
+_DEFPIN_AVR(24, 16, D); _DEFPIN_AVR(25, 128, D); _DEFPIN_AVR(26, 16, B); _DEFPIN_AVR(27, 32, B);
+_DEFPIN_AVR(28, 64, B); _DEFPIN_AVR(29, 64, D); _DEFPIN_AVR(30, 32, D);
#define SPI_DATA 16
#define SPI_CLOCK 15
@@ -269,7 +295,7 @@ _DEFPIN_AVR(20, 32, F); _DEFPIN_AVR(21, 16, F); _DEFPIN_AVR(22, 2, F); _DEFPIN_A
// PD3/PD5
#define SPI_UART1_DATA 1
-#define SPI_UART1_CLOCK 24
+#define SPI_UART1_CLOCK 30
#endif
diff --git a/power_mgt.h b/power_mgt.h
index 9ff6f208..5d0ec61c 100644
--- a/power_mgt.h
+++ b/power_mgt.h
@@ -1,6 +1,8 @@
#ifndef POWER_MGT_H
#define POWER_MGT_H
+#include "FastLED.h"
+
#include "pixeltypes.h"
FASTLED_NAMESPACE_BEGIN
diff --git a/release_notes.md b/release_notes.md
index 2258ab46..e59d1de4 100644
--- a/release_notes.md
+++ b/release_notes.md
@@ -1,4 +1,9 @@
-FastLED3.1.1pre
+FastLED3.1.2pre
+===============
+
+* Add SK6822 timings
+
+FastLED3.1.1
============
* Enabled RFDuino/nrf51822 hardware SPI support
* Fix edge case bug w/HSV palette blending
@@ -7,6 +12,10 @@ FastLED3.1.1pre
* Roll power management into FastLED.show/delay directly
* Support for adafruit pixies on arduino type platforms that have SoftwareSerial
* TODO: support hardware serial on platforms that have it available
+* Add UCS2903 timings
+* Preliminary CPixelView/CRGBSet code - more flexible treatment of groups of arrays
+ * https://github.com/FastLED/FastLED/wiki/RGBSet-Reference
+
FastLED3.1.0
============