FastLED 3.10.6
Loading...
Searching...
No Matches
binary_dither.h
Go to the documentation of this file.
1#pragma once
2
65
66#include "fl/stl/int.h"
68#include "fl/stl/noexcept.h"
69#include "fl/math/math8.h"
70#include "fl/math/scale8.h"
71
73#ifndef MAX_LIKELY_UPDATE_RATE_HZ
74#define MAX_LIKELY_UPDATE_RATE_HZ 400
75#endif
76
78#ifndef MIN_ACCEPTABLE_DITHER_RATE_HZ
79#define MIN_ACCEPTABLE_DITHER_RATE_HZ 50
80#endif
81
83#ifndef UPDATES_PER_FULL_DITHER_CYCLE
84#define UPDATES_PER_FULL_DITHER_CYCLE (MAX_LIKELY_UPDATE_RATE_HZ / MIN_ACCEPTABLE_DITHER_RATE_HZ)
85#endif
86
95#ifndef RECOMMENDED_VIRTUAL_BITS
96#define RECOMMENDED_VIRTUAL_BITS ((UPDATES_PER_FULL_DITHER_CYCLE>1) + \
97 (UPDATES_PER_FULL_DITHER_CYCLE>2) + \
98 (UPDATES_PER_FULL_DITHER_CYCLE>4) + \
99 (UPDATES_PER_FULL_DITHER_CYCLE>8) + \
100 (UPDATES_PER_FULL_DITHER_CYCLE>16) + \
101 (UPDATES_PER_FULL_DITHER_CYCLE>32) + \
102 (UPDATES_PER_FULL_DITHER_CYCLE>64) + \
103 (UPDATES_PER_FULL_DITHER_CYCLE>128) )
104#endif
105
107#ifndef VIRTUAL_BITS
108#define VIRTUAL_BITS RECOMMENDED_VIRTUAL_BITS
109#endif
110
111namespace fl {
112
115 enum { kEnabled = 1 };
116
121 frame &= (0x01 << VIRTUAL_BITS) - 1;
122 u8 q = 0;
123 if (frame & 0x01) { q |= 0x80; }
124 if (frame & 0x02) { q |= 0x40; }
125 if (frame & 0x04) { q |= 0x20; }
126 if (frame & 0x08) { q |= 0x10; }
127 if (frame & 0x10) { q |= 0x08; }
128 if (frame & 0x20) { q |= 0x04; }
129 if (frame & 0x40) { q |= 0x02; }
130 if (frame & 0x80) { q |= 0x01; }
131 if (VIRTUAL_BITS < 8) {
132 q += 0x01 << (7 - VIRTUAL_BITS);
133 }
134 return q;
135 }
136
139 u8 d = fl::scale8(q, range);
140#if (FASTLED_SCALE8_FIXED == 1)
141 // Adjust for the fixed scale8's rounding up.
142 if (d) { --d; }
143#endif
144 return d;
145 }
146
151 static FASTLED_FORCE_INLINE void init(u8 (&d)[3], u8 (&e)[3], const u8 (&scale)[3],
152 u8 frame) FL_NO_EXCEPT {
153 const u8 q = phase(frame);
154 for (int i = 0; i < 3; ++i) {
155 // Computed in a local and stored once; re-reading `e[i]` after
156 // the `d[i]` store cost 36 B on AVR (#4672).
157 const u8 s = scale[i];
158 u8 range = s ? (256 / s) + 1 : 0;
159 d[i] = offset(q, range);
160 if (range) { --range; }
161 e[i] = range;
162 }
163 }
164
167 static FASTLED_FORCE_INLINE void reseed(u8 (&d)[3], const u8 (&e)[3], u8 frame) FL_NO_EXCEPT {
168 const u8 q = phase(frame);
169 for (int i = 0; i < 3; ++i) {
170 // `e[i]` is init's range less one; zero only for an unlit
171 // channel, which carries no offset.
172 d[i] = e[i] ? offset(q, static_cast<u8>(e[i] + 1)) : 0;
173 }
174 }
175
176 static FASTLED_FORCE_INLINE void clear(u8 (&d)[3], u8 (&e)[3]) FL_NO_EXCEPT {
177 d[0] = d[1] = d[2] = e[0] = e[1] = e[2] = 0;
178 }
179
180 static FASTLED_FORCE_INLINE bool active(const u8 (&e)[3]) FL_NO_EXCEPT {
181 return (e[0] | e[1] | e[2]) != 0;
182 }
183
186 static FASTLED_FORCE_INLINE void step(u8 (&d)[3], const u8 (&e)[3]) FL_NO_EXCEPT {
187 d[0] = e[0] - d[0];
188 d[1] = e[1] - d[1];
189 d[2] = e[2] - d[2];
190 }
191
193 static FASTLED_FORCE_INLINE void stepChannel(u8 (&d)[3], const u8 (&e)[3], int c) FL_NO_EXCEPT {
194 d[c] = e[c] - d[c];
195 }
196
199 return b ? fl::qadd8(b, d) : 0;
200 }
201};
202
205struct NoDither {
206 enum { kEnabled = 0 };
207
210 static FASTLED_FORCE_INLINE void init(u8 (&d)[3], u8 (&e)[3], const u8 (&)[3], u8) FL_NO_EXCEPT {
211 clear(d, e);
212 }
213 static FASTLED_FORCE_INLINE void reseed(u8 (&)[3], const u8 (&)[3], u8) FL_NO_EXCEPT {}
214 static FASTLED_FORCE_INLINE void clear(u8 (&d)[3], u8 (&e)[3]) FL_NO_EXCEPT {
215 d[0] = d[1] = d[2] = e[0] = e[1] = e[2] = 0;
216 }
217 static FASTLED_FORCE_INLINE bool active(const u8 (&)[3]) FL_NO_EXCEPT { return false; }
218 static FASTLED_FORCE_INLINE void step(u8 (&)[3], const u8 (&)[3]) FL_NO_EXCEPT {}
219 static FASTLED_FORCE_INLINE void stepChannel(u8 (&)[3], const u8 (&)[3], int) FL_NO_EXCEPT {}
221};
222
229#if defined(NO_DITHERING) && (NO_DITHERING == 1)
230typedef NoDither Dither;
231#else
233#endif
234
235} // namespace fl
fl::UISlider scale("Scale", 4,.1, 4,.1)
#define VIRTUAL_BITS
Alias for RECOMMENDED_VIRTUAL_BITS.
#define FASTLED_FORCE_INLINE
Legacy compatibility header for 8-bit math functions.
Legacy compatibility header for 8-bit scaling functions.
unsigned char u8
Definition stdint.h:131
InputGamut g FL_NO_EXCEPT
Definition rgbw.h:121
BinaryDither Dither
The policy this build uses.
Base definition for an LED controller.
Definition crgb.hpp:179
static FASTLED_FORCE_INLINE bool active(const u8(&e)[3]) FL_NO_EXCEPT
static FASTLED_FORCE_INLINE void stepChannel(u8(&d)[3], const u8(&e)[3], int c) FL_NO_EXCEPT
step for a single channel (drivers that pre-step their first byte).
static FASTLED_FORCE_INLINE void reseed(u8(&d)[3], const u8(&e)[3], u8 frame) FL_NO_EXCEPT
Re-point d at frame, keeping the ranges init left in e.
static FASTLED_FORCE_INLINE void clear(u8(&d)[3], u8(&e)[3]) FL_NO_EXCEPT
static FASTLED_FORCE_INLINE u8 apply(u8 b, u8 d) FL_NO_EXCEPT
Add the offset to a source byte, before scaling. Black is never lifted.
static FASTLED_FORCE_INLINE u8 phase(u8 frame) FL_NO_EXCEPT
The frame's offset pattern value Q: frame wrapped to VIRTUAL_BITS, bit-reversed so consecutive frames...
static FASTLED_FORCE_INLINE u8 offset(u8 q, u8 range) FL_NO_EXCEPT
Q scaled into [0, range): the offset for one channel.
static FASTLED_FORCE_INLINE void init(u8(&d)[3], u8(&e)[3], const u8(&scale)[3], u8 frame) FL_NO_EXCEPT
Set up e from the per-channel brightness scale and d from frame.
static FASTLED_FORCE_INLINE void step(u8(&d)[3], const u8(&e)[3]) FL_NO_EXCEPT
Next pixel: toggle each offset to its complement in [0, e], so neighbours dither in opposite directio...
Temporal binary dithering over caller-owned d[3]/e[3].
static FASTLED_FORCE_INLINE void init(u8(&d)[3], u8(&e)[3], const u8(&)[3], u8) FL_NO_EXCEPT
static FASTLED_FORCE_INLINE void reseed(u8(&)[3], const u8(&)[3], u8) FL_NO_EXCEPT
static FASTLED_FORCE_INLINE void clear(u8(&d)[3], u8(&e)[3]) FL_NO_EXCEPT
static FASTLED_FORCE_INLINE u8 apply(u8 b, u8) FL_NO_EXCEPT
static FASTLED_FORCE_INLINE void stepChannel(u8(&)[3], const u8(&)[3], int) FL_NO_EXCEPT
static FASTLED_FORCE_INLINE void step(u8(&)[3], const u8(&)[3]) FL_NO_EXCEPT
static FASTLED_FORCE_INLINE u8 offset(u8, u8) FL_NO_EXCEPT
static FASTLED_FORCE_INLINE bool active(const u8(&)[3]) FL_NO_EXCEPT
static FASTLED_FORCE_INLINE u8 phase(u8) FL_NO_EXCEPT
The disabled policy: same interface, no work.