192 lines
5.1 KiB
C++
192 lines
5.1 KiB
C++
#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 + FASTTRIGON_8BIT(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;
|
|
}
|