Added snowfall animation
This commit is contained in:
parent
8e9124c884
commit
aa56e36f3f
|
@ -3,3 +3,4 @@
|
|||
#include "ConnectingAnimation.h"
|
||||
#include "ConnectionEstablishedAnimation.h"
|
||||
#include "FireAnimation.h"
|
||||
#include "SnowfallAnimation.h"
|
||||
|
|
|
@ -14,13 +14,15 @@ class AnimationController
|
|||
enum DefaultAnimation {
|
||||
FIRE_HOT = 0,
|
||||
FIRE_COLD = 1,
|
||||
SNOWFALL = 2,
|
||||
|
||||
NUM_DEFAULT_ANIMATIONS
|
||||
};
|
||||
|
||||
static const constexpr std::array<const char*, NUM_DEFAULT_ANIMATIONS> AnimationNames{
|
||||
"Hot Fire",
|
||||
"Cold Fire"
|
||||
"Cold Fire",
|
||||
"Snowfall"
|
||||
};
|
||||
|
||||
AnimationController(Fader *fader);
|
||||
|
|
58
include/Animation/SnowfallAnimation.h
Normal file
58
include/Animation/SnowfallAnimation.h
Normal file
|
@ -0,0 +1,58 @@
|
|||
#pragma once
|
||||
|
||||
#include <random>
|
||||
#include <list>
|
||||
|
||||
#include "Animation.h"
|
||||
|
||||
#include "fasttrigon.h"
|
||||
|
||||
class SnowfallAnimation : public Animation
|
||||
{
|
||||
public:
|
||||
SnowfallAnimation(Fader *fader);
|
||||
|
||||
void loop(uint64_t frame) override;
|
||||
|
||||
void stop(void) override
|
||||
{
|
||||
m_stopping = true;
|
||||
}
|
||||
|
||||
void reset(void) override;
|
||||
|
||||
private:
|
||||
class SnowFlake
|
||||
{
|
||||
public:
|
||||
SnowFlake(Fader *fader, int32_t phase, int32_t vertSpeed, int32_t baseStrip);
|
||||
|
||||
void move(void);
|
||||
bool has_fallen(void) const;
|
||||
|
||||
void render(void) const;
|
||||
|
||||
int32_t cur_strip(void) const;
|
||||
|
||||
private:
|
||||
Fader *m_fader;
|
||||
|
||||
int32_t m_phase;
|
||||
int32_t m_phaseIncPerFrame;
|
||||
int32_t m_vertSpeed; // in 1/256 LEDs
|
||||
|
||||
int32_t m_radius; // in 1/256 LEDs
|
||||
int32_t m_radiusSq; // in 1/256 LEDs
|
||||
|
||||
int32_t m_basePosStrip; // in 1/256 strips (for speed only)
|
||||
int32_t m_posStrip; // in 1/256 strips
|
||||
int32_t m_posLED; // in 1/256 LEDs
|
||||
};
|
||||
|
||||
std::list<SnowFlake> m_snowFlakes;
|
||||
std::vector<uint32_t> m_snowLevel; // level for each strip in 1/256 LEDs
|
||||
|
||||
std::default_random_engine m_gen;
|
||||
|
||||
bool m_stopping;
|
||||
};
|
191
src/Animation/SnowfallAnimation.cpp
Normal file
191
src/Animation/SnowfallAnimation.cpp
Normal file
|
@ -0,0 +1,191 @@
|
|||
#include <algorithm>
|
||||
|
||||
#include "Animation/SnowfallAnimation.h"
|
||||
|
||||
/********* SnowFlake *********/
|
||||
|
||||
SnowfallAnimation::SnowFlake::SnowFlake(Fader *fader, int32_t phase, int32_t vertSpeed, int32_t baseStrip)
|
||||
: m_fader(fader),
|
||||
m_phase(phase),
|
||||
m_phaseIncPerFrame(fasttrigon::LUT_SIZE/60),
|
||||
m_vertSpeed(vertSpeed),
|
||||
m_radius(282), // 1.1 * 256
|
||||
m_radiusSq(310),
|
||||
m_basePosStrip(baseStrip*256),
|
||||
m_posStrip(baseStrip*256),
|
||||
m_posLED(fader->modules_per_strip()*256 + m_radius*2)
|
||||
{}
|
||||
|
||||
void SnowfallAnimation::SnowFlake::move(void)
|
||||
{
|
||||
m_phase += m_phaseIncPerFrame;
|
||||
if(m_phase > fasttrigon::LUT_SIZE) {
|
||||
m_phase -= fasttrigon::LUT_SIZE;
|
||||
}
|
||||
|
||||
m_posStrip = m_basePosStrip + 2*fasttrigon::fastsin(m_phase);
|
||||
m_posLED -= m_vertSpeed;
|
||||
}
|
||||
|
||||
bool SnowfallAnimation::SnowFlake::has_fallen(void) const
|
||||
{
|
||||
return m_posLED < -(2*m_radius);
|
||||
}
|
||||
|
||||
int32_t SnowfallAnimation::SnowFlake::cur_strip(void) const
|
||||
{
|
||||
int32_t strip = m_posStrip / 256;
|
||||
|
||||
uint32_t nstrip = m_fader->strips();
|
||||
|
||||
while(strip < 0) {
|
||||
strip += nstrip;
|
||||
}
|
||||
while(strip >= nstrip) {
|
||||
strip -= nstrip;
|
||||
}
|
||||
|
||||
return strip;
|
||||
}
|
||||
|
||||
void SnowfallAnimation::SnowFlake::render(void) const
|
||||
{
|
||||
int32_t min_strip = (m_posStrip - m_radius) / 256;
|
||||
int32_t max_strip = (m_posStrip + m_radius + 256) / 256;
|
||||
int32_t min_led = (m_posLED - m_radius) / 256;
|
||||
int32_t max_led = (m_posLED + m_radius + 256) / 256;
|
||||
|
||||
for(int32_t strip = min_strip; strip <= max_strip; strip++) {
|
||||
int32_t finestrip = strip * 256;
|
||||
|
||||
for(int32_t led = min_led; led <= max_led; led++) {
|
||||
if(led < 0 || led >= m_fader->modules_per_strip()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int32_t fineled = led * 256;
|
||||
|
||||
int32_t diststrip = finestrip - m_posStrip;
|
||||
int32_t distled = fineled - m_posLED;
|
||||
|
||||
int32_t distsq = (diststrip*diststrip + distled*distled) / 256;
|
||||
|
||||
// brightness target range: 0..255
|
||||
int32_t brightness = 256 - 256 * distsq / m_radiusSq;
|
||||
|
||||
if(brightness < 0) {
|
||||
continue; // this pixel is too far away -> no effect
|
||||
}
|
||||
|
||||
int32_t normstrip = strip;
|
||||
int32_t nstrips = m_fader->strips();
|
||||
while(normstrip < 0) {
|
||||
normstrip += nstrips;
|
||||
}
|
||||
while(normstrip >= nstrips) {
|
||||
normstrip -= nstrips;
|
||||
}
|
||||
|
||||
m_fader->add_color(normstrip, led,
|
||||
Fader::Color{
|
||||
0,
|
||||
0,
|
||||
static_cast<int16_t>(32*brightness/256),
|
||||
static_cast<int16_t>(48*brightness/256)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/********* SnowfallAnimation *********/
|
||||
|
||||
SnowfallAnimation::SnowfallAnimation(Fader *fader)
|
||||
: Animation(fader),
|
||||
m_snowLevel(fader->strips(), 0)
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
void SnowfallAnimation::loop(uint64_t frame)
|
||||
{
|
||||
std::size_t nled = m_fader->modules_per_strip();
|
||||
std::size_t nstrip = m_fader->strips();
|
||||
|
||||
// update snow level on ground from fallen snow flakes
|
||||
for(auto &flake: m_snowFlakes) {
|
||||
if(flake.has_fallen()) {
|
||||
m_snowLevel[flake.cur_strip()] += 65536/5;
|
||||
}
|
||||
}
|
||||
|
||||
// remove fallen snow flakes
|
||||
m_snowFlakes.remove_if(
|
||||
[](const SnowFlake &flake) { return flake.has_fallen(); });
|
||||
|
||||
if(!m_stopping) {
|
||||
// spawn new snowflakes
|
||||
std::uniform_int_distribution<uint32_t> spawnRNG(0, 999);
|
||||
if(spawnRNG(m_gen) < 50) {
|
||||
std::uniform_int_distribution<int32_t> phaseRNG(0, fasttrigon::LUT_SIZE-1);
|
||||
std::uniform_int_distribution<int32_t> vertSpeedRNG(13, 38); // 0.05..0.15
|
||||
std::uniform_int_distribution<int32_t> baseStripRNG(0, nstrip-1);
|
||||
|
||||
m_snowFlakes.emplace_back(SnowFlake{
|
||||
m_fader,
|
||||
phaseRNG(m_gen),
|
||||
vertSpeedRNG(m_gen),
|
||||
baseStripRNG(m_gen)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// clear the frame buffer
|
||||
m_fader->set_color(Fader::Color{0, 0, 0, 0});
|
||||
|
||||
// move snow flakes and render
|
||||
for(auto &flake: m_snowFlakes) {
|
||||
flake.move();
|
||||
flake.render();
|
||||
}
|
||||
|
||||
// render snow on the ground and melt it
|
||||
for(size_t strip = 0; strip < nstrip; strip++) {
|
||||
size_t led = 0;
|
||||
size_t level = m_snowLevel[strip];
|
||||
size_t brightness;
|
||||
|
||||
while(level > 0 && led < nled) {
|
||||
if(level >= 65536) {
|
||||
brightness = 65536;
|
||||
} else {
|
||||
brightness = level;
|
||||
}
|
||||
|
||||
m_fader->add_color(strip, led,
|
||||
Fader::Color{
|
||||
0,
|
||||
static_cast<int16_t>(8 * brightness / 65535),
|
||||
static_cast<int16_t>(32 * brightness / 65535),
|
||||
static_cast<int16_t>(12 * brightness / 65535)
|
||||
});
|
||||
|
||||
level -= brightness;
|
||||
led++;
|
||||
}
|
||||
|
||||
// "melt" the snow
|
||||
m_snowLevel[strip] = m_snowLevel[strip] * 999 / 1000;
|
||||
}
|
||||
|
||||
m_fader->update();
|
||||
|
||||
if(m_stopping && m_snowFlakes.empty()) {
|
||||
m_running = false;
|
||||
}
|
||||
}
|
||||
|
||||
void SnowfallAnimation::reset(void)
|
||||
{
|
||||
m_stopping = false;
|
||||
m_running = true;
|
||||
}
|
Loading…
Reference in a new issue