Added Fireworks animation – Happy new year!

This commit is contained in:
Thomas Kolb 2019-12-31 23:39:09 +01:00
parent 6a71074b4b
commit 905c3fce7b
5 changed files with 210 additions and 1 deletions

View file

@ -7,3 +7,4 @@
#include "FadeToColorAnimation.h"
#include "ImageScrollerAnimation.h"
#include "MatrixCodeAnimation.h"
#include "FireworkAnimation.h"

View file

@ -17,6 +17,7 @@ class AnimationController
SNOWFALL = 2,
FONT_TEST = 3,
MATRIX_CODE = 4,
FIREWORK = 5,
NUM_DEFAULT_ANIMATIONS
};
@ -26,7 +27,8 @@ class AnimationController
"Cold Fire",
"Snowfall",
"Font Test",
"Matrix Code"
"Matrix Code",
"Fireworks"
};
AnimationController(Fader *fader);

View file

@ -0,0 +1,64 @@
#pragma once
#include <random>
#include <list>
#include <array>
#include "Animation.h"
class FireworkRocket
{
private:
enum LaunchPhase {
PHASE_RISING,
PHASE_SPREADING,
PHASE_DONE
};
std::array<int, 6> m_flareXPos;
std::array<int, 6> m_flareYPos;
LaunchPhase m_phase;
int m_rocketXPos;
int m_rocketYPos;
int m_targetHeight;
int m_riseSpeed;
uint64_t m_spreadStartFrame;
Fader::Color m_color;
public:
FireworkRocket(int start_x, int target_height, int rise_speed, const Fader::Color &color);
void move(uint64_t frame);
void render(Fader *fader);
bool done(void) const { return m_phase == PHASE_DONE; }
};
class FireworkAnimation : public Animation
{
public:
FireworkAnimation(Fader *fader, int vspeed = 128, int spawn_rate = 8);
void loop(uint64_t frame) override;
void stop(void) override
{
m_stopping = true;
}
void reset(void) override;
private:
std::default_random_engine m_gen;
std::list<FireworkRocket> m_rockets;
int m_vspeed;
int m_spawnRate; // average pixels per second
bool m_stopping;
};

View file

@ -53,6 +53,10 @@ void AnimationController::changeAnimation(AnimationController::DefaultAnimation
changeAnimation(std::unique_ptr<Animation>(new MatrixCodeAnimation(m_fader)), transition);
break;
case FIREWORK:
changeAnimation(std::unique_ptr<Animation>(new FireworkAnimation(m_fader, 64, 1)), transition);
break;
case FONT_TEST:
{
Bitmap bmp(0, 0);

View file

@ -0,0 +1,138 @@
#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::fastcos(fasttrigon::LUT_SIZE / 12 + i * fasttrigon::LUT_SIZE / m_flareXPos.size()) / 2;
int speedY = 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;
}