esp32-sk6812/src/Animation/FireworkAnimation.cpp

139 lines
4.1 KiB
C++

#include "Animation/FireworkAnimation.h"
#include <iostream>
#include "fasttrigon.h"
FireworkRocket::FireworkRocket(int start_x, int target_height, int rise_speed, const Fader::Color &color)
: m_phase(PHASE_RISING), m_rocketXPos(start_x*256), m_rocketYPos(0*256), m_targetHeight(target_height*256), m_riseSpeed(rise_speed), m_color(color)
{
}
void FireworkRocket::move(uint64_t frame)
{
switch(m_phase) {
case PHASE_RISING:
if(m_rocketYPos < m_targetHeight) {
m_rocketYPos += m_riseSpeed;
} else {
for(size_t i = 0; i < m_flareXPos.size(); i++) {
m_flareXPos[i] = m_rocketXPos;
m_flareYPos[i] = m_rocketYPos;
}
m_spreadStartFrame = frame;
m_phase = PHASE_SPREADING;
}
break;
case PHASE_SPREADING:
for(size_t i = 0; i < m_flareXPos.size(); i++) {
int speedX = FASTTRIGON_8BIT(fasttrigon::fastcos(fasttrigon::LUT_SIZE / 12 + i * fasttrigon::LUT_SIZE / m_flareXPos.size())) / 2;
int speedY = FASTTRIGON_8BIT(fasttrigon::fastsin(fasttrigon::LUT_SIZE / 12 + i * fasttrigon::LUT_SIZE / m_flareXPos.size())) / 2;
m_flareXPos[i] += speedX;
m_flareYPos[i] += speedY;
}
if((frame - m_spreadStartFrame) >= 20) {
m_phase = PHASE_DONE;
}
break;
case PHASE_DONE:
break;
}
}
void FireworkRocket::render(Fader *fader)
{
uint32_t nled = fader->modules_per_strip();
uint32_t nstrip = fader->strips();
switch(m_phase) {
case PHASE_RISING:
fader->add_color(m_rocketXPos/256, m_rocketYPos/256, Fader::Color{32, 16, 0, 0});
break;
case PHASE_SPREADING:
for(size_t i = 0; i < m_flareXPos.size(); i++) {
int x = (m_flareXPos[i]/256 + nstrip) % nstrip;
int y = (m_flareYPos[i]/256);
if(y >= nled || y < 0) {
continue;
}
fader->add_color(x, y, m_color);
}
break;
case PHASE_DONE:
// nothing more
break;
}
}
FireworkAnimation::FireworkAnimation(Fader *fader, int vspeed, int spawn_rate)
: Animation(fader),
m_vspeed(vspeed),
m_spawnRate(spawn_rate)
{
reset();
}
void FireworkAnimation::loop(uint64_t frame)
{
//int nled = m_fader->modules_per_strip();
int nstrip = m_fader->strips();
if(frame == 0) {
m_fader->set_fadestep(16);
}
m_fader->fade_color(Fader::Color{0,0,0,0});
// create new pixels
std::uniform_int_distribution<int> spawnRNG(0, (60*nstrip / m_spawnRate) - 1);
std::uniform_int_distribution<int> vspeedRNG(m_vspeed - 16, m_vspeed + 16);
for(int i = 0; i < nstrip; i++) {
if(spawnRNG(m_gen) == 0) {
std::uniform_int_distribution<int> stripRNG(0, nstrip-1);
std::uniform_int_distribution<int> heightRNG(5, 13);
std::uniform_int_distribution<int16_t> colorRNG(0, 15);
int16_t colorMask = colorRNG(m_gen);
m_rockets.emplace_back(FireworkRocket{stripRNG(m_gen), heightRNG(m_gen), vspeedRNG(m_gen),
Fader::Color{
255 * ((colorMask >> 3) & 0x01),
255 * ((colorMask >> 2) & 0x01),
255 * ((colorMask >> 1) & 0x01),
128 * ((colorMask >> 0) & 0x01)
}});
}
}
// move all pixels down and render them
for(auto &rocket: m_rockets) {
rocket.move(frame);
rocket.render(m_fader);
}
m_rockets.remove_if(
[](const FireworkRocket &r) { return r.done(); });
m_fader->update();
m_running = !m_stopping || m_fader->something_changed();
}
void FireworkAnimation::reset(void)
{
m_rockets.clear();
m_stopping = false;
m_running = true;
}