185 lines
4.8 KiB
C++
185 lines
4.8 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 (_xv < 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() {
|
|
delete window;
|
|
for (int i=0; i<settings.effects.firework.sparks; i++) {
|
|
delete _sparks[i];
|
|
}
|
|
delete _dot;
|
|
}
|