Lamp-Da 0.1
A compact lantern project
Loading...
Searching...
No Matches
fadeout.hpp
Go to the documentation of this file.
1
5#ifndef MODES_ANIM_FADEOUT_HPP
6#define MODES_ANIM_FADEOUT_HPP
7
9
10namespace lampda::modes::anims {
12namespace fadeout {
13
19template<uint8_t MaskBuffId, uint8_t minMaskValue = 0> struct GravityDissolve
20{
21 void reset(auto& ctx)
22 {
23 // set all values to max: no masking
24 ctx.lamp.template fillTempBuffer<MaskBuffId>(UINT8_MAX);
25 // reset particles
26 particuleSystem.reset();
27 particuleSystem.set_max_particle_count(20);
28
29 latestProgress = -1.0;
30 latestProgressTime = 0;
31 particlesToDepopPerIteration = 0.0;
32 depopRate = 0.0;
33 particlesDropped = 0;
34 }
35
36 void loop(auto& ctx, uint32_t color)
37 {
38 // find the particles to depop
39 depopRate += particlesToDepopPerIteration;
40 // time to depop one of more particle
41 float integer;
42 const float fractional = modf(depopRate, &integer);
43 if (integer >= 1.0 and particlesDropped < ctx.lamp.ledCount)
44 {
45 // time to depop !
46 for (uint8_t depopIndex = 0; depopIndex < integer; depopIndex++)
47 {
48 // depop one particle, yay !
49 depop_one_particles(ctx);
50 }
51
52 // drop depop rate
53 depopRate = fractional;
54 }
55
56 // no updates if no particles
57 if (particuleSystem.get_number_of_active() > 0)
58 {
59 // depop particles out of bounds
60 static constexpr bool shouldKeepInLampBounds = false;
61 particuleSystem.iterate_no_collisions(
62 utils::vec3d(0.0, 0.0, -9.81 / 4.0), ctx.lamp.frameDurationMs / 1000.0, shouldKeepInLampBounds);
63 particuleSystem.depop_particules(recycle_particules_if_too_far);
64 particuleSystem.show(
65 [&](int16_t n, const Particle& particle) {
66 return color;
67 },
68 ctx.lamp);
69 }
70 }
71
76 void update_depop_rate(auto& ctx, const float progress)
77 {
78 const float updateDuration = static_cast<float>((ctx.lamp.now - latestProgressTime) / 1000.0);
79 if (updateDuration <= 0.0f)
80 return;
81 const float progressPerSecond = (progress - latestProgress) / updateDuration;
82
83 bool isValidCall = latestProgress >= 0 and updateDuration > 0;
84
85 // cancel the particle spawn
86 if (progress <= 0.0)
87 {
88 particlesToDepopPerIteration = 0.0;
89 latestProgress = -1;
90 isValidCall = false;
91 }
92 // update progress
93 else if (latestProgress != progress)
94 {
95 latestProgress = progress;
96 latestProgressTime = ctx.lamp.now;
97 }
98 else
99 isValidCall = false;
100
101 // not valid call, skip update
102 if (not isValidCall)
103 {
104 return;
105 }
106
107 const uint16_t particleMax = ctx.lamp.ledCount;
108 const float FramesFrequency = static_cast<float>(ctx.lamp.frameDurationMs / 1000.0);
109
110 const float particlesLeft = particleMax - particlesDropped;
111 const float trueProgress = 1.0 - particlesLeft / static_cast<float>(particleMax);
112 const float trueProgressDiff = progress - trueProgress;
113 // try to correct the update ratio by the lag or advance
114 const float correctedParticlesLeft = particleMax * (1.0 + trueProgressDiff);
115
116 // particles to depop per second is progress rate per second * particles left
117 particlesToDepopPerIteration = progressPerSecond * correctedParticlesLeft * FramesFrequency;
118 }
119
120protected:
121 static bool recycle_particules_if_too_far(const Particle& p)
122 {
123 static constexpr float bounds = 3.0;
124 return p.z_mm > LampTy::maxWidth * bounds or p.z_mm < -(LampTy::lampHeight_mm + LampTy::maxWidth * bounds);
125 }
126
127 bool depop_one_particles(auto& ctx)
128 {
129 bool isDepoped = false;
130 // progress goes from 0 to 1
131 // lamp turns off when 1 is reached
132 auto& buffer = ctx.lamp.template getTempBuffer<MaskBuffId>();
133 const auto bufferSize = ctx.lamp.ledCount;
134
135 // check lines by lines, keeping the first one with pixels left
136 for (int16_t y = ctx.lamp.maxHeight; y >= 0; y--)
137 {
138 // search for the first line with pixels sets, from bottom to top
139 uint8_t pixelSetCount = 0;
140 for (uint16_t x = 0; x <= ctx.lamp.maxWidth; x++)
141 {
142 const auto buffIndex = modes::to_strip(x, y);
143 if (buffIndex < 0 or buffIndex >= bufferSize)
144 continue;
145
146 const bool isPixelSet = buffer[buffIndex] > minMaskValue;
147 // check that at leat one pixel is still set
148 if (isPixelSet)
149 pixelSetCount += 1;
150 }
151
152 // found the first line with pixels left
153 if (pixelSetCount > 0)
154 {
155 // get a random led index in this
156 uint8_t selectedLed = lmpd_map<uint8_t>(rand(), 0, RAND_MAX, 0, pixelSetCount);
157 for (uint16_t x = 0; x <= ctx.lamp.maxWidth; x++)
158 {
159 const auto pixelId = modes::to_strip(x, y);
160 if (pixelId < 0 or pixelId >= bufferSize)
161 continue;
162
163 const bool isPixelSet = buffer[pixelId] > minMaskValue;
164 if (isPixelSet)
165 {
166 if (selectedLed == 0)
167 {
168 // drop this pixel
169 buffer[pixelId] = minMaskValue;
170 particlesDropped += 1;
171 isDepoped = true;
172
173 // spawn a new particle
174 const bool isCreated = particuleSystem.init_deferred_particules(1, [pixelId](size_t) {
175 return pixelId;
176 });
177 // Particle spawn can fail, it's only visual so ok
178 break;
179 }
180 selectedLed -= 1;
181 }
182 }
183 break;
184 }
185 }
186 if (not isDepoped)
187 {
188 bsp::lampda_print("Error: Could not depop particle");
189 return false;
190 }
191 return true;
192 }
193
194private:
195 //
196 float latestProgress = -1.0;
197 uint32_t latestProgressTime = 0;
198
199 float particlesToDepopPerIteration = 0.0;
200 float depopRate = 0.0;
201 size_t particlesDropped = 0;
202 modes::ParticleSystem particuleSystem = modes::ParticleSystem();
203};
204
205} // namespace fadeout
206} // namespace lampda::modes::anims
207
208#endif
uint16_t get_number_of_active() const
Return the number of active particles.
Definition: particle_system.hpp:208
bool init_deferred_particules(uint8_t maxParticlesToPop, const std::function< int16_t(size_t)> &positionGeneratorFunction)
Init the particles from a initialization function, in a timed defered way.
Definition: particle_system.hpp:69
uint16_t show(const std::function< uint32_t(int16_t, const Particle &)> sample_color, LampTy &lamp)
Display this particle system.
Definition: particle_system.hpp:189
void iterate_no_collisions(const utils::vec3d &accelerationCartesian, const float deltaTime_s, const bool shouldContrain=true)
Advance the particle simulation, ignoring collisions.
Definition: particle_system.hpp:92
void set_max_particle_count(const uint16_t _particleCount)
Call when you want to change the particle count of the simulation Can be called once when starting th...
Definition: particle_system.hpp:44
uint16_t depop_particules(const std::function< bool(const Particle &)> &shouldDepopFunction)
Filter particles depending on condition.
Definition: particle_system.hpp:161
void reset()
reset system to zero count
Definition: particle_system.hpp:34
void lampda_print(const char *format,...)
C linkage to print functions.
Definition: text_out.cpp:206
static constexpr uint16_t to_strip(uint16_t, uint16_t)
convert grid coordinates to strip index
Definition: lamp_type.hpp:1104
Define a particle system, with particle based logic.
Define a particle in 3D space. it has a position and speed.
Definition: particle.hpp:37
float z_mm
height, in millimeters.
Definition: particle.hpp:204
Make an animation disapear with gravity.
Definition: fadeout.hpp:20
void update_depop_rate(auto &ctx, const float progress)
Update the drop rate.
Definition: fadeout.hpp:76
static constexpr float lampHeight_mm
Computation of the lamp height.
Definition: lamp_type.hpp:441
static constexpr uint16_t maxWidth
(indexable) Width of "pixel space" w/ lamp taken as a LED matrix
Definition: lamp_type.hpp:370
3d vector in any space
Definition: vector_math.h:54