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;
30 }
31
32 void loop(auto& ctx, uint32_t color)
33 {
34 // find the particles to depop
35 depopRate += particlesToDepopPerIteration;
36 // time to depop one of more particle
37 float integer;
38 const float fractional = modf(depopRate, &integer);
39 if (integer >= 1.0 and particlesDropped < ctx.lamp.ledCount)
40 {
41 // time to depop !
42 for (uint8_t depopIndex = 0; depopIndex < integer; depopIndex++)
43 {
44 // depop one particle, yay !
45 depop_one_particles(ctx);
46 }
47
48 // drop depop rate
49 depopRate = fractional;
50 }
51
52 // no updats if no particles
53 if (particuleSystem.get_number_of_active() > 0)
54 {
55 // depop particles out of bounds
56 static constexpr bool shouldKeepInLampBounds = false;
57 particuleSystem.iterate_no_collisions(
58 utils::vec3d(0.0, 0.0, -9.81 / 4.0), ctx.lamp.frameDurationMs / 1000.0, shouldKeepInLampBounds);
59 particuleSystem.depop_particules(recycle_particules_if_too_far);
60 particuleSystem.show(
61 [&](int16_t n, const Particle& particle) {
62 return color;
63 },
64 ctx.lamp);
65 }
66 }
67
72 void update_depop_rate(auto& ctx, const float progress)
73 {
74 const float updateDuration = static_cast<float>((ctx.lamp.now - latestProgressTime) / 1000.0);
75 const float progressPerSecond = (progress - latestProgress) / updateDuration;
76
77 bool isValidCall = latestProgress >= 0 and updateDuration > 0;
78
79 // cancel the particle spawn
80 if (progress <= 0.0)
81 {
82 particlesToDepopPerIteration = 0.0;
83 latestProgress = -1;
84 isValidCall = false;
85 }
86 // update progress
87 else if (latestProgress != progress)
88 {
89 latestProgress = progress;
90 latestProgressTime = ctx.lamp.now;
91 }
92 else
93 isValidCall = false;
94
95 // not valid call, skip update
96 if (not isValidCall)
97 {
98 return;
99 }
100
101 const uint16_t particleMax = ctx.lamp.ledCount;
102 const float FramesFrequency = static_cast<float>(ctx.lamp.frameDurationMs / 1000.0);
103
104 const float particlesLeft = particleMax - particlesDropped;
105 const float trueProgress = 1.0 - particlesLeft / static_cast<float>(particleMax);
106 const float trueProgressDiff = progress - trueProgress;
107 // try to correct the update ratio by the lag or advance
108 const float correctedParticlesLeft = particleMax * (1.0 + trueProgressDiff);
109
110 // particles to depop per second is progress rate per second * particles left
111 particlesToDepopPerIteration = progressPerSecond * correctedParticlesLeft * FramesFrequency;
112 }
113
114protected:
115 static bool recycle_particules_if_too_far(const Particle& p)
116 {
117 static constexpr float bounds = 3.0;
118 return p.z_mm > LampTy::maxWidth * bounds or p.z_mm < -(LampTy::lampHeight_mm + LampTy::maxWidth * bounds);
119 }
120
121 bool depop_one_particles(auto& ctx)
122 {
123 bool isDepoped = false;
124 // progress goes from 0 to 1
125 // lamp turns off when 1 is reached
126 auto& buffer = ctx.lamp.template getTempBuffer<MaskBuffId>();
127
128 // check lines by lines, keeping the first one with pixels left
129 for (int16_t y = ctx.lamp.maxHeight; y >= 0; y--)
130 {
131 // search for the first line with pixels sets, from bottom to top
132 uint8_t pixelSetCount = 0;
133 for (size_t x = 0; x <= ctx.lamp.maxWidth; x++)
134 {
135 const bool isPixelSet = buffer[modes::to_strip(x, y)] > minMaskValue;
136 // check that at leat one pixel is still set
137 if (isPixelSet)
138 pixelSetCount += 1;
139 }
140
141 // found the first line with pixels left
142 if (pixelSetCount > 0)
143 {
144 // get a random led index in this
145 uint8_t selectedLed = lmpd_map<uint8_t>(rand(), 0, RAND_MAX, 0, pixelSetCount);
146 for (size_t x = 0; x <= ctx.lamp.maxWidth; x++)
147 {
148 const auto& pixelId = modes::to_strip(x, y);
149 const bool isPixelSet = buffer[pixelId] > minMaskValue;
150 if (isPixelSet)
151 {
152 if (selectedLed == 0)
153 {
154 // drop this pixel
155 buffer[pixelId] = minMaskValue;
156 particlesDropped += 1;
157 // spawn a new particle
158 particuleSystem.init_deferred_particules(1, [pixelId](size_t) {
159 return pixelId;
160 });
161
162 isDepoped = true;
163 break;
164 }
165 selectedLed -= 1;
166 }
167 }
168 break;
169 }
170 }
171 if (not isDepoped)
172 {
173 platform::lampda_print("Error: Could not depop particle");
174 return false;
175 }
176 return true;
177 }
178
179private:
180 //
181 float latestProgress = -1.0;
182 uint32_t latestProgressTime = 0;
183
184 float particlesToDepopPerIteration = 0.0;
185 float depopRate = 0.0;
186 size_t particlesDropped = 0;
187 modes::ParticleSystem particuleSystem = modes::ParticleSystem();
188};
189
190} // namespace fadeout
191} // namespace lampda::modes::anims
192
193#endif
uint16_t get_number_of_active() const
Return the number of active particles.
Definition: particle_system.hpp:209
uint16_t show(const std::function< uint32_t(int16_t, const Particle &)> sample_color, LampTy &lamp)
Display this particle system.
Definition: particle_system.hpp:190
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:93
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:47
uint16_t depop_particules(const std::function< bool(const Particle &)> &shouldDepopFunction)
Filter particles depending on condition.
Definition: particle_system.hpp:162
void 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:72
void reset()
reset system to zero count
Definition: particle_system.hpp:34
static constexpr uint16_t to_strip(uint16_t, uint16_t)
convert grid coordinates to strip index
Definition: lamp_type.hpp:1100
void lampda_print(const char *format,...)
Definition: print.cpp:43
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:72
static constexpr float lampHeight_mm
Computation of the lamp height.
Definition: lamp_type.hpp:437
static constexpr uint16_t maxWidth
(indexable) Width of "pixel space" w/ lamp taken as a LED matrix
Definition: lamp_type.hpp:366
3d vector in any space
Definition: vector_math.h:54