| 94 | } |
| 95 | |
| 96 | void Luminova::draw(DrawContext context) { |
| 97 | // Fade + blur trails each frame |
| 98 | fadeToBlackBy(context.leds, mParams.fade_amount); |
| 99 | blur2d(context.leds, static_cast<fl::u8>(getWidth()), static_cast<fl::u8>(getHeight()), |
| 100 | mParams.blur_amount, mXyMap); |
| 101 | |
| 102 | // Spawn/overwrite one particle per frame, round-robin across pool |
| 103 | if (!mParticles.empty()) { |
| 104 | size_t idx = static_cast<size_t>(mTick % static_cast<fl::u32>(mParticles.size())); |
| 105 | resetParticle(mParticles[idx], mTick); |
| 106 | } |
| 107 | |
| 108 | // Update and draw all particles |
| 109 | for (size_t i = 0; i < mParticles.size(); ++i) { |
| 110 | Particle &p = mParticles[i]; |
| 111 | if (!p.alive) { |
| 112 | continue; |
| 113 | } |
| 114 | |
| 115 | // s *= 0.997 |
| 116 | p.s *= 0.997f; |
| 117 | if (p.s < 0.5f) { |
| 118 | p.alive = false; |
| 119 | continue; |
| 120 | } |
| 121 | |
| 122 | // angle jitter using 2D noise: (t/99, g) |
| 123 | float tOver99 = static_cast<float>(mTick) / 99.0f; |
| 124 | u8 n2 = inoise8(static_cast<u16>(tOver99 * 4096.0f), static_cast<u16>(p.g * 37)); |
| 125 | float n2c = (static_cast<int>(n2) - 128) / 255.0f; // ~ -0.5 .. +0.5 |
| 126 | p.a += (n2c) / 9.0f; |
| 127 | |
| 128 | float aa = p.a * static_cast<float>(p.f); |
| 129 | p.x += fl::cosf(aa); |
| 130 | p.y += fl::sinf(aa); |
| 131 | |
| 132 | plotSoftDot(context.leds, p.x, p.y, p.s); |
| 133 | } |
| 134 | |
| 135 | ++mTick; |
| 136 | } |
| 137 | |
| 138 | } // namespace fl |
nothing calls this directly
no test coverage detected