pitrix/src/effect_firework.cpp

184 lines
4.7 KiB
C++

// Based on https://gist.github.com/kriegsman/68929cbd1d6de4535b20
#include "effect_firework.h"
FireworkEffectDot::FireworkEffectDot(Window* w, FireworkEffect* e) {
_window = w;
_main = e;
show = 0;
type = FIREWORK_DOT_NONE;
_x = 0;
_y = _window->height - 1;
_xv = 0;
_yv = 0;
_r = 0;
_color.setRGB(0, 0, 0);
}
void FireworkEffectDot::_screenscale(accum88 a, byte n, byte& screen, byte& screenerr) {
byte ia = a >> 8;
screen = scale8(ia, n);
byte m = screen * (256 / n);
screenerr = (ia - m) * scale8(255, n);
}
int16_t FireworkEffectDot::_scale15by8_local(int16_t i, fract8 scale) {
int16_t result;
result = (int32_t)((int32_t) i*scale)/256;
return result;
}
void FireworkEffectDot::draw() {
if (!show) return;
byte ix, xe, xc;
byte iy, ye, yc;
_screenscale(_x, _window->width, ix, xe);
_screenscale(_y, _window->height, iy, ye);
xc = 255 - xe;
yc = 255 - ye;
CRGB c00 = CRGB(dim8_video( scale8( scale8( _color.r, yc), xc)),
dim8_video( scale8( scale8( _color.g, yc), xc)),
dim8_video( scale8( scale8( _color.b, yc), xc)));
CRGB c01 = CRGB(dim8_video( scale8( scale8( _color.r, ye), xc)),
dim8_video( scale8( scale8( _color.g, ye), xc)),
dim8_video( scale8( scale8( _color.b, ye), xc)));
CRGB c10 = CRGB(dim8_video( scale8( scale8( _color.r, yc), xe)),
dim8_video( scale8( scale8( _color.g, yc), xe)),
dim8_video( scale8( scale8( _color.b, yc), xe)));
CRGB c11 = CRGB(dim8_video( scale8( scale8( _color.r, ye), xe)),
dim8_video( scale8( scale8( _color.g, ye), xe)),
dim8_video( scale8( scale8( _color.b, ye), xe)));
_window->addPixelColor(ix, iy, &c00);
_window->addPixelColor(ix, iy-1, &c01);
_window->addPixelColor(ix+1, iy, &c10);
_window->addPixelColor(ix+1, iy-1, &c11);
}
void FireworkEffectDot::move() {
if (!show) return;
_yv -= settings.effects.firework.gravity;
_xv = _scale15by8_local(_xv, settings.effects.firework.drag);
_yv = _scale15by8_local(_yv, settings.effects.firework.drag);
if (type == FIREWORK_DOT_SPARK) {
_xv = _scale15by8_local(_xv, settings.effects.firework.drag);
_yv = _scale15by8_local(_yv, settings.effects.firework.drag);
_color.nscale8(255);
if (!_color) {
show = 0;
}
}
// Bounce if we hit the ground
if (_yv < 0 && _y - _window->height < (-_yv)) {
if (type == FIREWORK_DOT_SPARK) {
show = 0;
} else {
_yv = -_yv;
_yv = _scale15by8_local(_yv, settings.effects.firework.bounce);
if (_yv < 500) {
show = 0;
}
}
}
if (_yv < 300) {
if (type == FIREWORK_DOT_SHELL) {
if (_y < (uint16_t)0x8000) {
// boom
CRGB white(0xFFFFFF);
_window->clear(&white);
}
show = 0;
_main->skyburst(_x, _y, _xv, _yv, _color);
}
}
if (type == FIREWORK_DOT_SPARK) {
if ((_xv > 0 && _x>_xv) || (_xv < 0 && _x<(0xFFFF+_xv))) {
_x += _xv;
} else {
show = 0;
}
} else {
_x += _xv;
}
_y -= _yv;
}
void FireworkEffectDot::ground_launch() {
_xv = (int16_t)random16(600) - (int16_t)300;
_yv = 600 + random16(300 + (25 * _window->height));
_x = 0x8000;
_y = 0;
hsv2rgb_rainbow(CHSV(random8(), 240, 200), _color);
show = 1;
}
void FireworkEffectDot::sky_burst(accum88 basex, accum88 basey, saccum78 basedv, CRGB& basecolor) {
_xv = basedv + (int16_t)random16(2000) - (int16_t)1000;
_yv = (int16_t)random16(1500) - (int16_t)500;
_x = basex;
_y = basey;
_color = basecolor;
_color *= 4;
type = FIREWORK_DOT_SPARK;
show = 1;
}
void FireworkEffect::skyburst(accum88 x, accum88 y, saccum78 xv, saccum78 yv, CRGB c) {
_skyburst = 1;
_burst_x = x;
_burst_y = y;
_burst_xv = xv;
_burst_yv = yv;
_burst_color = c;
}
boolean FireworkEffect::can_be_shown_with_clock() {
return true;
}
void FireworkEffect::loop(uint16_t ms) {
window->clear();
_dot->move();
_dot->draw();
for (int i=0; i<settings.effects.firework.sparks; i++) {
_sparks[i]->move();
_sparks[i]->draw();
}
static uint16_t launch_countdown = 0;
if (_dot->show == 0) {
if (launch_countdown == 0) {
_dot->ground_launch();
_dot->type = FIREWORK_DOT_SHELL;
launch_countdown = random16(350) + 1;
} else {
launch_countdown--;
}
}
if (_skyburst) {
int nsparks = random8(settings.effects.firework.sparks / 2, settings.effects.firework.sparks + 1);
for (int i=0; i<nsparks; i++) {
_sparks[i]->sky_burst(_burst_x, _burst_y, _burst_yv, _burst_color);
_skyburst = 0;
}
}
}
FireworkEffect::FireworkEffect() {
_dot = new FireworkEffectDot(window, this);
_sparks = new FireworkEffectDot*[settings.effects.firework.sparks];
for (int i=0; i<settings.effects.firework.sparks; i++) {
_sparks[i] = new FireworkEffectDot(window, this);
}
}
FireworkEffect::~FireworkEffect() {
for (int i=0; i<settings.effects.firework.sparks; i++) {
delete _sparks[i];
}
delete _dot;
}