diff --git a/include/SimpleEffect.h b/include/SimpleEffect.h index e3b6315..9449022 100644 --- a/include/SimpleEffect.h +++ b/include/SimpleEffect.h @@ -1,21 +1,30 @@ #pragma once #include "Effect.h" #include "prototypes.h" +#include + +#define SE_CYCLE_COLORS 1 // Slowly cycle through the rainbow. +#define SE_RANDOM_PIXEL_COLORS 2 // Every pixel gets a random color every frame. +#define SE_ONLY_POSITIVE 4 // Only use colors, not white. This is equivalent to running your output through abs() +#define SE_FADEOUT 8 // Fades the old image out. Returning 0 doesn't change the pixel's value. +#define SE_RANDOM_STATIC_COLOR 16 // Sets a random static color at start of the effect. +#define SE_DEBUG 32 // Prints debug messages. class SimpleEffect : public Effect { protected: Window* window = &Window::window_full; // Use a full screen window per default. - boolean _fade_out = false; - boolean _random_colors = false; - boolean _cycle_color = true; uint8_t _color = 0; + uint16_t _flags; String _name; simple_effect_t _method; public: - SimpleEffect(String name, simple_effect_t method): _name { name }, _method { method } {}; - SimpleEffect* with_fadeout() { _fade_out=true; return this;} - SimpleEffect* with_random_colors() { _random_colors=true; return this;} - SimpleEffect* with_static_color(uint8_t color) { _cycle_color=false; _color=color; return this; } + SimpleEffect(String name, uint16_t flags, simple_effect_t method): _name { name }, _method { method } { + _flags = flags; + if (_flags & SE_RANDOM_STATIC_COLOR) { + _color = random8(); + _flags &= ~SE_CYCLE_COLORS & ~SE_RANDOM_PIXEL_COLORS; + } + }; void loop(uint16_t ms) override; String get_name() { return _name; }; boolean can_be_shown_with_clock() { return true; } diff --git a/include/effects.h b/include/effects.h index 1aae3b2..2cea6d5 100644 --- a/include/effects.h +++ b/include/effects.h @@ -4,7 +4,7 @@ #include "effects/clock.h" #include "effects/timer.h" -#define SIMPLE_EFFECT [](accum88 t, uint16_t i, uint8_t x, uint8_t y)->int8_t +#define SIMPLE_EFFECT(name, use_in_cycle, flags, ...) {name, use_in_cycle, [](){ return new SimpleEffect(name, flags, [](double t, uint16_t i, uint8_t x, uint8_t y)->double __VA_ARGS__ ); }} struct EffectEntry { const char* name; diff --git a/include/prototypes.h b/include/prototypes.h index 4327e99..b8938ad 100644 --- a/include/prototypes.h +++ b/include/prototypes.h @@ -33,4 +33,4 @@ typedef struct { uint16_t y; } Coords; -typedef std::function simple_effect_t; \ No newline at end of file +typedef std::function simple_effect_t; \ No newline at end of file diff --git a/src/SimpleEffect.cpp b/src/SimpleEffect.cpp index 2193f2f..15d1f2a 100644 --- a/src/SimpleEffect.cpp +++ b/src/SimpleEffect.cpp @@ -1,21 +1,33 @@ #include "SimpleEffect.h" void SimpleEffect::loop(uint16_t ms) { - if (_fade_out) window->fadeToBlackBy(3); - accum88 t = millis() * 0x100 / 1000; + if (_flags & SE_FADEOUT) window->fadeToBlackBy(3); + double t = 0.001 * millis(); for(uint8_t x=0; xwidth; x++) for(uint8_t y=0; yheight; y++) { uint16_t i = y*window->width + x; - int8_t r = _method(t, i, x, y); - - if (_fade_out && r==0) { + double r = _method(t, i, x, y); + //if (i==0) Serial.printf("t=%f i=%d x=%d y=%d => r=%f, abs(r)=%d\n", t, i, x, y, r, abs(r)*255); + if ((_flags & SE_DEBUG) && i==17) Serial.printf("t=%f i=%d x=%d y=%d => r=%f, abs(r*255)=%d\n", t, i, x, y, r, (int)abs(r*255)); + if ((_flags & SE_FADEOUT) && r==0) { continue; } + // Clamp r between -1.0 and +1.0 + if (r<-1.0) { + r = -1.0; + } else if (r>1.0) { + r = 1.0; + } + + if (_flags & SE_ONLY_POSITIVE) { + r = abs(r); + } + CRGB color; - if (_random_colors) { - color = CHSV(random8(), 255, abs(r)*2); + if (_flags & SE_RANDOM_PIXEL_COLORS) { + color = CHSV(random8(), 255, abs(r*255)); } else { - color = CHSV(_cycle_color ? baseHue : _color, r<0?0:255, abs(r)*2); + color = CHSV(_flags & SE_CYCLE_COLORS ? baseHue : _color, r<0?0:255, abs(r*255)); } window->setPixel(x, y, &color); diff --git a/src/effects.cpp b/src/effects.cpp index 658b3cd..cdb4ef5 100644 --- a/src/effects.cpp +++ b/src/effects.cpp @@ -35,45 +35,48 @@ TimerEffect effect_timer; // We're using 0 instead of false to get a better visual difference between true and false. EffectEntry effects[] = { - /* 0 */ {"sinematrix3", true, [](){ return new Sinematrix3Effect(); }}, - /* 1 */ {"big_clock", true, [](){ return new BigClockEffect(); }}, - /* 2 */ {"clock", 0, [](){ return new ClockEffect(); }}, - /* 3 */ {"bell", 0, [](){ return AnimationEffect::Blinker("/bell.pia", 300, 0xFFFF00); }}, - /* 4 */ {"off", 0, [](){ return new StaticEffect(0x000000); }}, - /* 5 */ {"single_dynamic", true, [](){ return new SingleDynamicEffect(); }}, - /* 6 */ {"multi_dynamic", true, [](){ return new MultiDynamicEffect(); }}, - /* 7 */ {"big_dynamic", true, [](){ return new BigDynamicEffect(); }}, - /* 8 */ {"matrix", true, [](){ return new MatrixEffect(); }}, - /* 9 */ {"random_matrix", true, [](){ return new RandomMatrixEffect(); }}, - /* 10 */ {"rainbow_matrix", true, [](){ return new RainbowMatrixEffect(); }}, - /* 11 */ {"cycle", 0, [](){ return new CycleEffect(); }}, - /* 12 */ {"twirl", true, [](){ return new TwirlEffect(); }}, - /* 13 */ {"confetti", true, [](){ return (new SimpleEffect("confetti", SIMPLE_EFFECT{return random8()>252 ? 127 : 0;}))->with_fadeout();}}, - /* 14 */ {"rainbow_confetti", true, [](){ return (new SimpleEffect("rainbow_confetti", SIMPLE_EFFECT{return random8()>252 ? 127 : 0;}))->with_fadeout()->with_random_colors();}}, - /* 15 */ {"snake", true, [](){ return new SnakeEffect(); }}, - /* 16 */ {"firework", true, [](){ return new FireworkEffect(); }}, - /* 17 */ {"gol", true, [](){ return new GolEffect(); }}, - /* 18 */ {"pixel_clock", 0, [](){ return new PixelClockEffect(); }}, - /* 19 */ {"dvd", true, [](){ return new DvdEffect(); }}, - /* 20 */ {"analog_clock", 0, [](){ return new AnalogClockEffect(); }}, - /* 21 */ {"sines", true, [](){ return new SinesEffect(); }}, - /* 22 */ {"blur2d", true, [](){ return new Blur2DEffect(); }}, - /* 23 */ {"marquee", 0, [](){ return new MarqueeEffect(); }}, - /* 24 */ {"night_clock", 0, [](){ return new NightClockEffect(); }}, - /* 25 */ {"tv_static", 0, [](){ return new TvStaticEffect(); }}, - /* 26 */ {"sinematrix3_rainbow", true, [](){ return new Sinematrix3Effect(SINEMATRIX_COLOR_RAINBOW); }}, - /* 27 */ {"sinematrix3_purplefly", true, [](){ return new Sinematrix3Effect(SINEMATRIX_COLOR_PURPLEFLY); }}, - /* 28 */ {"lightspeed", true, [](){ return new LightspeedEffect(); }}, - /* 29 */ {"koopa", 0, [](){ return new AnimationEffect("/koopa.pia"); }}, - /* 30 */ {"cake", 0, [](){ return new AnimationEffect("/cake.pia"); }}, - /* 31 */ {"child", 0, [](){ return AnimationEffect::Blinker("/child.pia", 300, 0xFFFF00); }}, - /* 32 */ {"diamond", true, [](){ return new DiamondEffect(); }}, - /* 33 */ {"tpm2.net", 0, [](){ return new Tpm2NetEffect(); }}, - /* 34 */ {"slow_blinking", true, [](){ return new SimpleEffect("slow_blinking", SIMPLE_EFFECT{return sin8((t>>3) + ((((x+1)*(y+1)*i*15) >> 2) & 0xFF))-128;});}}, - /* 35 */ {"upwave", true, [](){ return new SimpleEffect("upwave", SIMPLE_EFFECT{return abs(cos8((t>>3)+(y<<4))-128);});}}, - /* 36 */ {"centerwave", true, [](){ return new SimpleEffect("centerwave", SIMPLE_EFFECT{return sin8((t>>1) - sqrt((x-4)*(x-4) + (y-7)*(y-7))*32)-128;});}}, + /* 0 */ {"sinematrix3", true, [](){ return new Sinematrix3Effect(); }}, + /* 1 */ {"big_clock", true, [](){ return new BigClockEffect(); }}, + /* 2 */ {"clock", 0, [](){ return new ClockEffect(); }}, + /* 3 */ {"bell", 0, [](){ return AnimationEffect::Blinker("/bell.pia", 300, 0xFFFF00); }}, + /* 4 */ {"off", 0, [](){ return new StaticEffect(0x000000); }}, + /* 5 */ {"single_dynamic", true, [](){ return new SingleDynamicEffect(); }}, + /* 6 */ {"multi_dynamic", true, [](){ return new MultiDynamicEffect(); }}, + /* 7 */ {"big_dynamic", true, [](){ return new BigDynamicEffect(); }}, + /* 8 */ {"matrix", true, [](){ return new MatrixEffect(); }}, + /* 9 */ {"random_matrix", true, [](){ return new RandomMatrixEffect(); }}, + /* 10 */ {"rainbow_matrix", true, [](){ return new RainbowMatrixEffect(); }}, + /* 11 */ {"cycle", 0, [](){ return new CycleEffect(); }}, + /* 12 */ {"twirl", true, [](){ return new TwirlEffect(); }}, + /* 13 */ SIMPLE_EFFECT("confetti", true, SE_CYCLE_COLORS | SE_FADEOUT, {return random8()>252?1:0;}), + /* 14 */ SIMPLE_EFFECT("rainbow_confetti", true, SE_RANDOM_PIXEL_COLORS | SE_FADEOUT, {return random8()>252?1:0;}), + /* 15 */ {"snake", true, [](){ return new SnakeEffect(); }}, + /* 16 */ {"firework", true, [](){ return new FireworkEffect(); }}, + /* 17 */ {"gol", true, [](){ return new GolEffect(); }}, + /* 18 */ {"pixel_clock", 0, [](){ return new PixelClockEffect(); }}, + /* 19 */ {"dvd", true, [](){ return new DvdEffect(); }}, + /* 20 */ {"analog_clock", 0, [](){ return new AnalogClockEffect(); }}, + /* 21 */ {"sines", true, [](){ return new SinesEffect(); }}, + /* 22 */ {"blur2d", true, [](){ return new Blur2DEffect(); }}, + /* 23 */ {"marquee", 0, [](){ return new MarqueeEffect(); }}, + /* 24 */ {"night_clock", 0, [](){ return new NightClockEffect(); }}, + /* 25 */ {"tv_static", 0, [](){ return new TvStaticEffect(); }}, + /* 26 */ {"sinematrix3_rainbow", true, [](){ return new Sinematrix3Effect(SINEMATRIX_COLOR_RAINBOW); }}, + /* 27 */ {"sinematrix3_purplefly", true, [](){ return new Sinematrix3Effect(SINEMATRIX_COLOR_PURPLEFLY); }}, + /* 28 */ {"lightspeed", true, [](){ return new LightspeedEffect(); }}, + /* 29 */ {"koopa", 0, [](){ return new AnimationEffect("/koopa.pia"); }}, + /* 30 */ {"cake", 0, [](){ return new AnimationEffect("/cake.pia"); }}, + /* 31 */ {"child", 0, [](){ return AnimationEffect::Blinker("/child.pia", 300, 0xFFFF00); }}, + /* 32 */ {"diamond", true, [](){ return new DiamondEffect(); }}, + /* 33 */ {"tpm2.net", 0, [](){ return new Tpm2NetEffect(); }}, + /* 34 */ SIMPLE_EFFECT("slow_blinking", true, SE_CYCLE_COLORS, {return sin(t + (x+1)*(y+1)*i);} ), + /* 35 */ SIMPLE_EFFECT("upwave", true, SE_CYCLE_COLORS, {return (cos(t+y/2));} ), + /* 36 */ SIMPLE_EFFECT("centerwave", true, SE_CYCLE_COLORS, {return sin(t*2 - sqrt((x-4)*(x-4) + (y-7)*(y-7)));} ), + /* 37 */ SIMPLE_EFFECT("sineline", true, SE_RANDOM_STATIC_COLOR, {return sin(x/2)-sin(x-t)-y+6;} ), + /* 38 */ SIMPLE_EFFECT("barbershop", true, SE_RANDOM_STATIC_COLOR, {return 1*cos(0.8*i-t*5);} ), + /* 39 */ SIMPLE_EFFECT("zigzag", true, SE_CYCLE_COLORS, { return cos(cos(x+y)-y*cos(t/8+x/16));} ), }; -const uint8_t effects_size = 37; +const uint8_t effects_size = 40; Effect* select_effect(const char* name) {