Rewrote effect firework. Now it kinda works.

This commit is contained in:
Fabian Schlenz 2019-09-25 06:30:03 +02:00
parent 6ba2854a8d
commit 711719921a
2 changed files with 234 additions and 10 deletions

View File

@ -1,7 +1,61 @@
#pragma once #pragma once
#include "prototypes.h"
#include "functions.h"
#include "Effect.h" #include "Effect.h"
enum FireworkDotType { FIREWORK_DOT_NONE, FIREWORK_DOT_SHELL, FIREWORK_DOT_SPARK };
#define EFFECT_FIREWORK_DRAG 255
#define EFFECT_FIREWORK_BOUNCE 200
#define EFFECT_FIREWORK_GRAVITY 10
#define EFFECT_FIREWORK_SPARKS 12
class FireworkEffect;
class FireworkEffectDot {
private:
Window* _window;
FireworkEffect* _main;
accum88 _x;
accum88 _y;
saccum78 _xv;
saccum78 _yv;
accum88 _r;
CRGB _color;
void _screenscale(accum88 a, byte n, byte& screen, byte& screenerr);
int16_t _scale15by8_local(int16_t i, fract8 scale);
public:
byte show;
FireworkDotType type;
FireworkEffectDot(Window* w, FireworkEffect* e);
void draw();
void move();
void ground_launch();
void sky_burst(accum88 basex, accum88 basey, saccum78 basedv, CRGB& basecolor);
};
class FireworkEffect : public Effect { class FireworkEffect : public Effect {
private:
Window* window = new Window(0, 0, LED_WIDTH, LED_HEIGHT-6);
bool _skyburst = 0;
accum88 _burst_x;
accum88 _burst_y;
saccum78 _burst_xv;
saccum78 _burst_yv;
CRGB _burst_color;
FireworkEffectDot* _dot;
FireworkEffectDot* _sparks[EFFECT_FIREWORK_SPARKS];
public:
FireworkEffect();
~FireworkEffect();
void skyburst(accum88 x, accum88 y, saccum78 xv, saccum78 yv, CRGB c);
boolean supports_window = true;
boolean can_be_shown_with_clock();
void loop(); void loop();
}; };

View File

@ -1,13 +1,183 @@
// Based on https://gist.github.com/kriegsman/68929cbd1d6de4535b20
#include "effect_firework.h" #include "effect_firework.h"
#include "my_fastled.h"
#include "functions.h" FireworkEffectDot::FireworkEffectDot(Window* w, FireworkEffect* e) {
#include "config.h" _window = w;
_main = e;
show = 0;
type = FIREWORK_DOT_NONE;
_x = 0;
_y = 0;
_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 -= EFFECT_FIREWORK_GRAVITY;
_xv = _scale15by8_local(_xv, EFFECT_FIREWORK_DRAG);
_yv = _scale15by8_local(_yv, EFFECT_FIREWORK_DRAG);
if (type == FIREWORK_DOT_SPARK) {
_xv = _scale15by8_local(_xv, EFFECT_FIREWORK_DRAG);
_yv = _scale15by8_local(_yv, EFFECT_FIREWORK_DRAG);
_color.nscale8(255);
if (!_color) {
show = 0;
}
}
// Bounce if we hit the ground
if (_xv < 0 && _y < (-_yv)) {
if (type == FIREWORK_DOT_SPARK) {
show = 0;
} else {
_yv = -_yv;
_yv = _scale15by8_local(_yv, EFFECT_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() { void FireworkEffect::loop() {
blur(EFFECT_FIREWORK_BLUR); window->clear();
fadeToBlackBy(leds, LED_COUNT, EFFECT_FIREWORK_FADEOUT_SPEED); _dot->move();
_dot->draw();
for (int i=0; i<EFFECT_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 (random8(EFFECT_FIREWORK_SHOT_CHANCE)==0) { if (_skyburst) {
leds[random16(LED_COUNT)] = CHSV(random8(), 255, 255); int nsparks = random8(EFFECT_FIREWORK_SPARKS / 2, EFFECT_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);
for (int i=0; i<EFFECT_FIREWORK_SPARKS; i++) {
_sparks[i] = new FireworkEffectDot(window, this);
}
}
FireworkEffect::~FireworkEffect() {
delete window;
for (int i=0; i<EFFECT_FIREWORK_SPARKS; i++) {
delete _sparks[i];
}
delete _dot;
}