Permalink
Browse files

Fixed loss-of-precision bug in pixel blending. Pixel blending should …

…be a little smoother now and free from error noise in the low bits. This includes palette colors returned from ColorFromPalette, which are now slightly smoother. Also introduced a new lib8tion function, blend8( byte, byte, fract8). The new pixel blending should have negligible effect on code size, and it is ever so slightly faster than the old version with the error. Fixes #404.
  • Loading branch information...
kriegsman committed Jan 20, 2017
1 parent 94e46e3 commit 60f90b69902c0515bedcd1cddbd0c61be10f902a
Showing with 67 additions and 4 deletions.
  1. +9 −1 colorutils.cpp
  2. +11 −3 fastled_config.h
  3. +1 −0 keywords.txt
  4. +46 −0 lib8tion/math8.h
View
@@ -234,6 +234,8 @@ CRGB& nblend( CRGB& existing, const CRGB& overlay, fract8 amountOfOverlay )
return existing;
}
#if 0
// Old blend method which unfortunately had some rounding errors
fract8 amountOfKeep = 255 - amountOfOverlay;
existing.red = scale8_LEAVING_R1_DIRTY( existing.red, amountOfKeep)
@@ -244,7 +246,13 @@ CRGB& nblend( CRGB& existing, const CRGB& overlay, fract8 amountOfOverlay )
+ scale8_LEAVING_R1_DIRTY( overlay.blue, amountOfOverlay);
cleanup_R1();
#else
// Corrected blend method, with no loss-of-precision rounding errors
existing.red = blend8( existing.red, overlay.red, amountOfOverlay);
existing.green = blend8( existing.green, overlay.green, amountOfOverlay);
existing.blue = blend8( existing.blue, overlay.blue, amountOfOverlay);
#endif
return existing;
}
View
@@ -33,10 +33,18 @@
// had a problem where scale8(255,255) would give you 254. This is now fixed, and that
// fix is enabled by default. However, if for some reason you have code that is not
// working right as a result of this (e.g. code that was expecting the old scale8 behavior)
// you can disable it here
// you can disable it here.
#define FASTLED_SCALE8_FIXED 1
// define FASTLED_SCALE8_FIXED 0
// #define FASTLED_SCALE8_FIXED 0
// Use this toggle whether to use 'fixed' FastLED pixel blending, including ColorFromPalette.
// The prior pixel blend functions had integer-rounding math errors that led to
// small errors being inadvertently added to the low bits of blended colors, including colors
// retrieved from color palettes using LINEAR_BLEND. This is now fixed, and the
// fix is enabled by default. However, if for some reason you wish to run with the old
// blending, including the integer rounding and color errors, you can disable the bugfix here.
#define FASTLED_BLEND_FIXED 1
// #define FASTLED_BLEND_FIXED 0
// Use this to determine how many times FastLED will attempt to re-transmit a frame if interrupted
// for too long by interrupts.
View
@@ -109,6 +109,7 @@ triwave8 KEYWORD2
quadwave8 KEYWORD2
cubicwave8 KEYWORD2
sqrt16 KEYWORD2
blend8 KEYWORD2
# Color util methods
blend KEYWORD2
View
@@ -1,6 +1,8 @@
#ifndef __INC_LIB8TION_MATH_H
#define __INC_LIB8TION_MATH_H
#include "scale8.h"
///@ingroup lib8tion
///@defgroup Math Basic math operations
@@ -406,5 +408,49 @@ LIB8STATIC uint8_t sqrt16(uint16_t x)
return low - 1;
}
/// blend a variable proproportion(0-255) of one byte to another
/// @param a - the starting byte value
/// @param b - the byte value to blend toward
/// @param amountOfB - the proportion (0-255) of b to blend
/// @returns a byte value between a and b, inclusive
#if (FASTLED_BLEND_FIXED == 1)
LIB8STATIC uint8_t blend8( uint8_t a, uint8_t b, uint8_t amountOfB)
{
uint16_t partial;
uint8_t result;
uint8_t amountOfA = 255 - amountOfB;
partial = (a * amountOfA);
#if (FASTLED_SCALE8_FIXED == 1)
partial += a;
#endif
partial += (b * amountOfB);
#if (FASTLED_SCALE8_FIXED == 1)
partial += b;
#endif
result = partial >> 8;
return result;
}
#else
LIB8STATIC uint8_t blend8( uint8_t a, uint8_t b, uint8_t amountOfB)
{
// This version loses precision in the integer math
// and can actually return results outside of the range
// from a to b. Its use is not recommended.
uint8_t result;
uint8_t amountOfA = 255 - amountOfB;
result = scale8_LEAVING_R1_DIRTY( a, amountOfA)
+ scale8_LEAVING_R1_DIRTY( b, amountOfB);
cleanup_R1();
return result;
}
#endif
///@}
#endif

0 comments on commit 60f90b6

Please sign in to comment.