5#ifndef MODES_ANIM_FADEOUT_HPP
6#define MODES_ANIM_FADEOUT_HPP
10namespace lampda::modes::anims {
28 template<
typename ContextType, u
int8_t MaskBuffId, u
int8_t minMaskValue>
29 static bool depop_one(ContextType& ctx, uint32_t& pixelId)
31 auto& buffer = ctx.lamp.template getTempBuffer<MaskBuffId>();
32 const auto bufferSize = ctx.lamp.ledCount;
35 for (int16_t y = ctx.lamp.maxHeight; y >= 0; y--)
38 uint8_t pixelSetCount = 0;
39 for (uint16_t x = 0; x <= ctx.lamp.maxWidth; x++)
42 if (buffIndex < 0 or buffIndex >= bufferSize)
44 if (buffer[buffIndex] > minMaskValue)
49 if (pixelSetCount > 0)
52 uint8_t selectedLed = lmpd_map<uint8_t>(rand(), 0, RAND_MAX, 0, pixelSetCount);
53 for (uint16_t x = 0; x <= ctx.lamp.maxWidth; x++)
56 if (tempPixelId < 0 or tempPixelId >= bufferSize)
58 if (buffer[tempPixelId] > minMaskValue)
62 pixelId = tempPixelId;
84 template<
typename ContextType, u
int8_t MaskBuffId, u
int8_t minMaskValue>
87 auto& buffer = ctx.lamp.template getTempBuffer<MaskBuffId>();
88 const auto bufferSize = ctx.lamp.ledCount;
90 if (y >= ctx.lamp.maxHeight or (y + 1) > ctx.lamp.maxHeight)
97 if (pixelId >= 0 and pixelId < bufferSize)
99 if (buffer[pixelId] > minMaskValue)
104 if (pixelIdOffseted >= 0 and pixelIdOffseted < bufferSize)
106 if (buffer[pixelIdOffseted] > minMaskValue)
112 template<
typename ContextType, u
int8_t MaskBuffId, u
int8_t minMaskValue>
113 static bool depop_one(ContextType& ctx, uint32_t& pixelId)
115 auto& buffer = ctx.lamp.template getTempBuffer<MaskBuffId>();
116 const auto bufferSize = ctx.lamp.ledCount;
117 uint8_t orphanCount = 0;
119 int16_t minYLine = ctx.lamp.maxHeight;
120 int16_t maxYLine = 0;
123 for (int16_t y = ctx.lamp.maxHeight; y >= 0; y--)
125 bool hasSetPixels =
false;
126 bool hasOrphanPixels =
false;
127 for (uint16_t x = 0; x <= ctx.lamp.maxWidth; x++)
130 if (tempPixelId < 0 or tempPixelId >= bufferSize)
132 if (buffer[tempPixelId] > minMaskValue)
137 if (not has_pixel_below<ContextType, MaskBuffId, minMaskValue>(ctx, x, y))
140 hasOrphanPixels =
true;
142 minYLine = min<int16_t>(minYLine, y);
143 maxYLine = max<int16_t>(maxYLine, y);
148 if (hasSetPixels and not hasOrphanPixels)
154 if (orphanCount <= 0)
160 uint8_t selectedLed = lmpd_map<uint8_t>(rand(), 0, RAND_MAX, 0, orphanCount);
163 for (int16_t y = maxYLine; y >= minYLine; y--)
165 for (uint16_t x = 0; x <= ctx.lamp.maxWidth; x++)
168 if (tempPixelId < 0 or tempPixelId >= bufferSize)
170 if (buffer[tempPixelId] > minMaskValue)
173 if (not has_pixel_below<ContextType, MaskBuffId, minMaskValue>(ctx, x, y))
175 if (selectedLed == 0)
177 pixelId = tempPixelId;
195template<u
int8_t MaskBuffId,
typename DropMode = DropModeOrphansOnly, u
int8_t minMaskValue = 0>
struct GravityDissolve
197 void reset(
auto& ctx)
200 ctx.lamp.template fillTempBuffer<MaskBuffId>(UINT8_MAX);
202 particuleSystem.reset();
203 particuleSystem.set_max_particle_count(20);
205 latestProgress = -1.0;
206 latestProgressTime = 0;
207 particlesToDepopPerIteration = 0.0;
209 particlesDropped = 0;
212 void loop(
auto& ctx, uint32_t color)
215 depopRate += particlesToDepopPerIteration;
218 const float fractional = modf(depopRate, &integer);
219 if (integer >= 1.0 and particlesDropped < ctx.lamp.ledCount)
222 for (uint8_t depopIndex = 0; depopIndex < integer; depopIndex++)
225 depop_one_particles(ctx);
229 depopRate = fractional;
233 if (particuleSystem.get_number_of_active() > 0)
236 static constexpr bool shouldKeepInLampBounds =
false;
237 particuleSystem.iterate_no_collisions(
238 utils::vec3d(0.0, 0.0, -9.81 / 4.0), ctx.lamp.frameDurationMs / 1000.0, shouldKeepInLampBounds);
239 particuleSystem.depop_particules(recycle_particules_if_too_far);
240 particuleSystem.show(
241 [&](int16_t n,
const Particle& particle) {
255 const float progress = expectedProgress / gracePeriod;
257 const float updateDuration =
static_cast<float>((ctx.lamp.now - latestProgressTime) / 1000.0);
258 if (updateDuration <= 0.0f)
261 const float progressPerSecond = (progress - latestProgress) / updateDuration;
262 bool isValidCall = latestProgress >= 0 and updateDuration > 0;
267 particlesToDepopPerIteration = 0.0;
268 latestProgress = 0.0;
272 else if (latestProgress != progress)
274 latestProgress = progress;
275 latestProgressTime = ctx.lamp.now;
286 const uint16_t particleMax = ctx.lamp.ledCount;
287 const float frameFrequency = 1000.0 / ctx.lamp.frameDurationMs;
289 const float particlesLeft = particleMax - particlesDropped;
290 const float trueProgress = 1.0 - particlesLeft /
static_cast<float>(particleMax);
293 const float expectedParticlesDropped = particleMax * progress;
294 const float particleDeficit = expectedParticlesDropped -
static_cast<float>(particlesDropped);
296 const float remainingProgressRatio = 1.0 - progress;
300 if (remainingProgressRatio > 0.0f && particlesLeft > 0.0f)
303 float normalDepopRate = progressPerSecond * particlesLeft / frameFrequency;
307 float deficitCatchupRate = 0.0f;
308 if (progressPerSecond > 0.0f)
310 const float timeToFinish = remainingProgressRatio / progressPerSecond;
311 deficitCatchupRate = particleDeficit / timeToFinish / frameFrequency;
315 particlesToDepopPerIteration = normalDepopRate + deficitCatchupRate;
317 else if (particlesLeft > 0.0f && progress >= 1.0f)
320 particlesToDepopPerIteration = particlesLeft;
324 particlesToDepopPerIteration = 0.0;
328 const float maxParticlesToDepop = particlesLeft;
329 if (particlesToDepopPerIteration > maxParticlesToDepop)
330 particlesToDepopPerIteration = maxParticlesToDepop;
334 static bool recycle_particules_if_too_far(
const Particle& p)
336 static constexpr float bounds = 3.0;
340 bool depop_one_particles(
auto& ctx)
342 auto& buffer = ctx.lamp.template getTempBuffer<MaskBuffId>();
343 const auto bufferSize = ctx.lamp.ledCount;
347 if (not DropMode::template depop_one<
decltype(ctx), MaskBuffId, minMaskValue>(ctx, pixelId) or pixelId < 0 or
348 pixelId >= bufferSize)
355 buffer[pixelId] = minMaskValue;
356 particlesDropped += 1;
359 const bool isCreated = particuleSystem.init_deferred_particules(1, [pixelId](
size_t) {
368 static constexpr float gracePeriod = 0.99;
370 float latestProgress = -1.0;
371 uint32_t latestProgressTime = 0;
373 float particlesToDepopPerIteration = 0.0;
374 float depopRate = 0.0;
375 size_t particlesDropped = 0;
void lampda_print(const char *format,...)
C linkage to print functions.
Definition: text_out.cpp:227
static constexpr uint16_t to_strip(uint16_t, uint16_t)
convert grid coordinates to strip index
Definition: lamp_type.hpp:1104
static ParticleSystem & get_shared_particle_system()
Access the main level shared particle system.
Definition: particle_system.hpp:261
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
Drop mode policy: remove particles line by line from bottom to top Only pixels from the lowest non-em...
Definition: fadeout.hpp:23
static bool depop_one(ContextType &ctx, uint32_t &pixelId)
Find and depop one particle according to this mode.
Definition: fadeout.hpp:29
Drop mode policy: remove only "orphan" particles A particle can only be dropped if there is no other ...
Definition: fadeout.hpp:80
static bool has_pixel_below(ContextType &ctx, uint16_t x, int16_t y)
Check if a pixel at (x, y) has a pixel below it.
Definition: fadeout.hpp:85
Make an animation disapear with gravity.
Definition: fadeout.hpp:196
void update_depop_rate(auto &ctx, const float expectedProgress)
Update the drop rate.
Definition: fadeout.hpp:252
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