FastLED 3.10.8
Loading...
Searching...
No Matches
wave_simulation.h
Go to the documentation of this file.
1/*
2This is the WaveSimulation API. These classes allow flexible super sampling
3to achieve much better visual quality. They will also run the simulator
4update multiple times in order to achieve consistent speed between super
5sampling factors.
6
7A super sampling value of 2x will give the best results for the CPU consumption
8as most artifacts will be averaged out at this resolution.
9
10Based on works and code by Shawn Silverman.
11*/
12
13#pragma once
14
15#include "fl/math/math.h" // for fl::min, fl::max
17
18#include "fl/math/grid.h"
19#include "fl/stl/unique_ptr.h" // For unique_ptr
20#include "fl/math/supersample.h"
21#include "fl/stl/int.h"
22#include "fl/stl/noexcept.h"
23
24namespace fl {
25
27
28// -----------------------------------------------------------------------------
29// New supersampled 1D simulation class.
30//
31// This class mimics the supersampling logic of WaveSimulation2D.
32// The constructor accepts the desired downsampled length and a supersampling
33// multiplier (via a SuperSample enum). Internally, it creates a high-resolution
34// simulation of size (multiplier * length), and its accessor methods average
35// over or replicate across the corresponding block of high-res cells.
37 public:
38 // Constructor:
39 // - length: desired downsampled grid length.
40 // - factor: supersampling multiplier (e.g., 1x, 2x, 4x, or 8x).
41 // Higher values yield better quality but are more cpu intensive.
42 // - speed and dampening are passed on to the internal simulation.
45 float speed = 0.16f, int dampening = 6) FL_NO_EXCEPT;
46
47 void init(u32 length, SuperSample factor, float speed, int dampening) FL_NO_EXCEPT;
48
50 if (u32(factor) == mMultiplier) {
51 return;
52 }
53 init(mOuterLength, factor, mSim->getSpeed(), mSim->getDampenening());
54 }
55
56 // Only applies to getu8().
58
60
61 // Delegate methods to the internal simulation.
62 void setSpeed(float speed) FL_NO_EXCEPT;
63 void setDampening(int damp) FL_NO_EXCEPT;
64 int getDampenening() const FL_NO_EXCEPT;
65 float getSpeed() const FL_NO_EXCEPT;
66
67 // Runs the simulator faster by updating it multiple times.
68 void setExtraFrames(u8 extra) FL_NO_EXCEPT;
69
70 // Downsampled getter for the floating point value at index x.
71 // It averages over the corresponding 'multiplier'-sized block in the
72 // high-res simulation.
73 float getf(fl::size x) const FL_NO_EXCEPT;
74
75 // Downsampled getter for the Q15 (fixed point) value at index x.
76 // It averages the multiplier cells of Q15 values.
77 i16 geti16(fl::size x) const FL_NO_EXCEPT;
78 i16 geti16Previous(fl::size x) const FL_NO_EXCEPT;
79
80 bool geti16All(fl::size x, i16 *curr, i16 *prev, i16 *diff) const FL_NO_EXCEPT;
81
82 // Downsampled getters for the 8-bit representations.
83 i8 geti8(fl::size x) const FL_NO_EXCEPT;
84
85 u8 getu8(fl::size x) const FL_NO_EXCEPT;
86
87 // Check if x is within the bounds of the outer (downsampled) simulation.
88 bool has(fl::size x) const FL_NO_EXCEPT;
89
90 // Upsampling setter: set the value at an outer grid cell x by replicating
91 // it to the corresponding multiplier cells in the high-res simulation.
92 void setf(fl::size x, float value) FL_NO_EXCEPT;
93
94 void setHalfDuplex(bool on) FL_NO_EXCEPT { mSim->setHalfDuplex(on); }
95
96 // Advance the simulation one time step.
97 void update() FL_NO_EXCEPT;
98
99 // Get the outer (downsampled) grid length.
100 u32 getLength() const FL_NO_EXCEPT;
101
103
104 private:
105 u32 mOuterLength; // Length of the downsampled simulation.
107 u32 mMultiplier; // Supersampling multiplier (e.g., 2, 4, or 8).
109 // Internal high-resolution simulation.
111};
112
114 public:
115 // Constructor:
116 // - W and H specify the desired inner grid size of the downsampled
117 // simulation.
118 // - 'factor' selects the supersampling mMultiplier (e.g., 2x, 4x, or 8x).
119 // Higher values yield better quality but are more cpu intensive.
120 // - Internally, the simulation is created with dimensions (factor*W x
121 // factor*H).
122 // - 'speed' and 'dampening' parameters are passed on to the internal
123 // simulation.
124 WaveSimulation2D(u32 W, u32 H,
126 float speed = 0.16f, float dampening = 6.0f) FL_NO_EXCEPT;
127
128 void init(u32 width, u32 height, SuperSample factor, float speed,
130
132
133 // Delegated simulation methods.
134 void setSpeed(float speed) FL_NO_EXCEPT;
135
136 void setExtraFrames(u8 extra) FL_NO_EXCEPT;
137
138 void setDampening(int damp) FL_NO_EXCEPT;
139
141
142 int getDampenening() const FL_NO_EXCEPT;
143
144 float getSpeed() const FL_NO_EXCEPT;
145
147 if (u32(factor) == mMultiplier) {
148 return;
149 }
150 // Preserve a user-set stencil across re-init. Without this, the
151 // wrapper's auto-select (NinePointIsotropic at multiplier >= 2)
152 // overwrites a toggle the user made via setStencil().
153 const LaplacianStencil saved_stencil = mSim->getStencil();
154 const bool stencil_was_user_set = mUserSetStencil;
155 init(mOuterWidth, mOuterHeight, factor, mSim->getSpeed(),
156 mSim->getDampenening());
157 if (stencil_was_user_set) {
158 mSim->setStencil(saved_stencil);
159 mUserSetStencil = true;
160 }
161 }
162
163 // Override the auto-selected Laplacian stencil. Calling this marks the
164 // choice as "user set" so subsequent setSuperSample() calls preserve
165 // it instead of re-applying the multiplier-based default. The default
166 // (no setStencil() ever called) is auto-selection: NinePointIsotropic
167 // at SuperSample >= 2X, FivePoint at 1X. See WaveSimulation2D_Real::
168 // setStencil() for the stencil semantics.
170 mSim->setStencil(s);
171 mUserSetStencil = true;
172 }
173 LaplacianStencil getStencil() const FL_NO_EXCEPT { return mSim->getStencil(); }
174
175 void setXCylindrical(bool on) FL_NO_EXCEPT { mSim->setXCylindrical(on); }
176
177 // Downsampled getter for the floating point value at (x,y) in the outer
178 // grid. It averages over the corresponding multiplier×multiplier block in
179 // the high-res simulation.
180 float getf(fl::size x, fl::size y) const FL_NO_EXCEPT;
181
182 // Downsampled getter for the Q15 (fixed point) value at (x,y).
183 // It averages the multiplier×multiplier block of Q15 values.
184 i16 geti16(fl::size x, fl::size y) const FL_NO_EXCEPT;
185 i16 geti16Previous(fl::size x, fl::size y) const FL_NO_EXCEPT;
186
187 bool geti16All(fl::size x, fl::size y, i16 *curr, i16 *prev,
188 i16 *diff) const FL_NO_EXCEPT;
189
190 // Downsampled getters for the 8-bit representations.
191 i8 geti8(fl::size x, fl::size y) const FL_NO_EXCEPT;
192
193 // Special function to get the value as a u8 for drawing / gradients.
194 // Ease out functions are applied to this when in half duplex mode.
195 u8 getu8(fl::size x, fl::size y) const FL_NO_EXCEPT;
196
197 // Check if (x,y) is within the bounds of the outer (downsampled) grid.
198 bool has(fl::size x, fl::size y) const FL_NO_EXCEPT;
199
200 // Upsampling setter: set the value at an outer grid cell (x,y) by
201 // replicating it to all cells of the corresponding multiplier×multiplier
202 // block in the high-res simulation.
203 void setf(fl::size x, fl::size y, float value) FL_NO_EXCEPT;
204
205 void seti16(fl::size x, fl::size y, i16 value) FL_NO_EXCEPT;
206
207 void setHalfDuplex(bool on) FL_NO_EXCEPT { mSim->setHalfDuplex(on); }
208
209 // Advance the simulation one time step.
210 void update() FL_NO_EXCEPT;
211
212 // Get the outer grid dimensions.
213 u32 getWidth() const FL_NO_EXCEPT;
214 u32 getHeight() const FL_NO_EXCEPT;
215
216 // Configure whether to use the change grid tracking optimization
217 void setUseChangeGrid(bool enabled) FL_NO_EXCEPT;
219
221
222 private:
223 u32 mOuterWidth; // Width of the downsampled (outer) grid.
224 u32 mOuterHeight; // Height of the downsampled (outer) grid.
226 u32 mMultiplier = 1; // Supersampling multiplier (e.g., 1, 2, 4, or 8).
228 bool mUseChangeGrid = false; // Whether to use change grid tracking (default: disabled for better visuals)
229 // True once setStencil() has been called from outside. Used to keep
230 // the user's stencil choice sticky across setSuperSample() re-inits.
231 bool mUserSetStencil = false;
232 // Internal high-resolution simulation.
234 fl::Grid<i16> mChangeGrid; // Needed for multiple updates.
235};
236
237} // namespace fl
uint16_t speed
Definition Noise.ino:72
static const int H
Definition PerfDisc.ino:21
static const int W
Definition PerfDisc.ino:20
u32 getLength() const FL_NO_EXCEPT
WaveSimulation1D_Real & real() FL_NO_EXCEPT
bool geti16All(fl::size x, i16 *curr, i16 *prev, i16 *diff) const FL_NO_EXCEPT
i16 geti16(fl::size x) const FL_NO_EXCEPT
fl::unique_ptr< WaveSimulation1D_Real > mSim
void setSpeed(float speed) FL_NO_EXCEPT
~WaveSimulation1D() FL_NO_EXCEPT=default
float getf(fl::size x) const FL_NO_EXCEPT
int getDampenening() const FL_NO_EXCEPT
WaveSimulation1D(u32 length, SuperSample factor=SuperSample::SUPER_SAMPLE_NONE, float speed=0.16f, int dampening=6) FL_NO_EXCEPT
void setDampening(int damp) FL_NO_EXCEPT
U8EasingFunction mU8Mode
void setEasingMode(U8EasingFunction mode) FL_NO_EXCEPT
float getSpeed() const FL_NO_EXCEPT
void setHalfDuplex(bool on) FL_NO_EXCEPT
i16 geti16Previous(fl::size x) const FL_NO_EXCEPT
void setf(fl::size x, float value) FL_NO_EXCEPT
i8 geti8(fl::size x) const FL_NO_EXCEPT
void setExtraFrames(u8 extra) FL_NO_EXCEPT
u8 getu8(fl::size x) const FL_NO_EXCEPT
void setSuperSample(SuperSample factor) FL_NO_EXCEPT
void update() FL_NO_EXCEPT
bool has(fl::size x) const FL_NO_EXCEPT
void init(u32 length, SuperSample factor, float speed, int dampening) FL_NO_EXCEPT
void setStencil(LaplacianStencil s) FL_NO_EXCEPT
bool has(fl::size x, fl::size y) const FL_NO_EXCEPT
u32 getWidth() const FL_NO_EXCEPT
i8 geti8(fl::size x, fl::size y) const FL_NO_EXCEPT
void setExtraFrames(u8 extra) FL_NO_EXCEPT
fl::Grid< i16 > mChangeGrid
WaveSimulation2D_Real & real() FL_NO_EXCEPT
void init(u32 width, u32 height, SuperSample factor, float speed, int dampening) FL_NO_EXCEPT
WaveSimulation2D(u32 W, u32 H, SuperSample factor=SuperSample::SUPER_SAMPLE_NONE, float speed=0.16f, float dampening=6.0f) FL_NO_EXCEPT
float getSpeed() const FL_NO_EXCEPT
void setUseChangeGrid(bool enabled) FL_NO_EXCEPT
int getDampenening() const FL_NO_EXCEPT
void setEasingMode(U8EasingFunction mode) FL_NO_EXCEPT
void seti16(fl::size x, fl::size y, i16 value) FL_NO_EXCEPT
i16 geti16(fl::size x, fl::size y) const FL_NO_EXCEPT
void setSpeed(float speed) FL_NO_EXCEPT
void setSuperSample(SuperSample factor) FL_NO_EXCEPT
u8 getu8(fl::size x, fl::size y) const FL_NO_EXCEPT
i16 geti16Previous(fl::size x, fl::size y) const FL_NO_EXCEPT
void setf(fl::size x, fl::size y, float value) FL_NO_EXCEPT
U8EasingFunction mU8Mode
bool geti16All(fl::size x, fl::size y, i16 *curr, i16 *prev, i16 *diff) const FL_NO_EXCEPT
void setHalfDuplex(bool on) FL_NO_EXCEPT
u32 getHeight() const FL_NO_EXCEPT
LaplacianStencil getStencil() const FL_NO_EXCEPT
float getf(fl::size x, fl::size y) const FL_NO_EXCEPT
void update() FL_NO_EXCEPT
void setXCylindrical(bool on) FL_NO_EXCEPT
bool getUseChangeGrid() const FL_NO_EXCEPT
~WaveSimulation2D() FL_NO_EXCEPT=default
fl::unique_ptr< WaveSimulation2D_Real > mSim
void setDampening(int damp) FL_NO_EXCEPT
fl::UISlider length("Length", 1.0f, 0.0f, 1.0f, 0.01f)
fl::UISlider dampening("Dampening", 6.0f, 0.0f, 10.0f, 0.1f)
unsigned char u8
Definition stdint.h:131
u8 u8 fract8 blur_amount FL_NO_EXCEPT
Definition blur.h:186
constexpr int type_rank< T >::value
u8 u8 height
Definition blur.h:186
U8EasingFunction
u8 width
Definition blur.h:186
signed char i8
Definition stdint.h:130
SuperSample
Definition supersample.h:4
Base definition for an LED controller.