class Effect { public: virtual void loop() {}; }; class Bell : public Effect { private: CRGB color_on = CRGB(0xFFFF00); CRGB color_off= CRGB(0x000000); boolean invert = false; public: void loop() { for(int y=0; y<16; y++) { for(int x=0; x<2; x++) { for(int z=0; z<8; z++) { leds[XYsafe(x*8+z, y)] = sprite_bell[y*2+x]>>(7-z) & 1 ^ invert ? color_on : color_off; } } } EVERY_N_MILLISECONDS(300) { invert = !invert; } } }; class Clock : public Effect { private: CRGB color_h = CRGB(0xFF0000); CRGB color_m = CRGB(0x00FF00); CRGB color_colon = CRGB(0xFFFF00); void drawNumber(uint8_t number, int x, int y, CRGB color) { char buffer[7]; sprintf(buffer, "%02d", number); drawText(buffer, x, y, color); } void drawText(char *text, int x, int y, CRGB color) { for (int i = 0; i < strlen(text); i++) { drawSprite(font_char(numbers4x7, text[i]), x + i * 4, y, color); } } unsigned char* font_char(unsigned char* font, char c) { return &font[(c - 48) * 4]; } void drawSprite(unsigned char* sprite, int xOffset, int yOffset, CRGB color) { for ( byte y = 0; y < 7; y++) { for ( byte x = 0; x < 4; x++) { bool on = (sprite[x] >> y & 1) * 255; if (on) { leds[ XYsafe(x + xOffset, y + yOffset) ] = color; } } } } public: Clock() {} void loop() { clear(); drawNumber(ntpClient.getHours(), 0, 0, color_h); drawNumber(ntpClient.getMinutes(), 8, 0, color_m); /*if (ntpClient.getSeconds() & 1) { leds[XYsafe(13, 2)] = color_colon; leds[XYsafe(13, 5)] = color_colon; }*/ drawNumber(ntpClient.getSeconds(), 8, 8, color_colon); } }; class SmallClock : public Effect { private: CRGB color_h = CRGB(0xFF0000); CRGB color_m = CRGB(0x00FF00); CRGB color_colon = CRGB(0xFFFF00); public: SmallClock() {} void loop() { clear(); int h = ntpClient.getHours(); drawDigit(numbers3x5, 3, 5, 0, 11, h/10, color_h); drawDigit(numbers3x5, 3, 5, 4, 11, h%10, color_h); int m = ntpClient.getMinutes(); drawDigit(numbers3x5, 3, 5, 9, 11, m/10, color_m); drawDigit(numbers3x5, 3, 5, 13, 11, m%10, color_m); if (ntpClient.getSeconds() & 1) { leds[XYsafe(7, 12)] = color_colon; leds[XYsafe(7, 14)] = color_colon; } } }; class Sinematrix3 : public Effect { private: double pangle = 0; double angle = 0; double sx = 0; double sy = 0; double tx = 0; double ty = 0; double cx = 0; double cy = 0; double rcx = 0; double rcy = 0; double angle2 = 0; double sx2 = 0; double sy2 = 0; double tx2 = 0; double ty2 = 0; double basecol = 0; double fx = 1.0/(LED_WIDTH/PI); double fy = 1.0/(LED_HEIGHT/PI); Matrix rotate; public: Sinematrix3() {} void loop() { pangle = addmodpi( pangle, 0.0133 + (angle/256) ); angle = cos(pangle) * PI; sx = addmodpi( sx, 0.00673 ); sy = addmodpi( sy, 0.00437 ); tx = addmodpi( tx, 0.00239 ); ty = addmodpi( ty, 0.00293 ); cx = addmodpi( cx, 0.00197 ); cy = addmodpi( cy, 0.00227 ); rcx = (LED_WIDTH/2) + (sin(cx) * LED_WIDTH); rcy = (LED_HEIGHT/2) + (sin(cy) * LED_HEIGHT); angle2 = addmodpi( angle2, 0.0029 ); sx2 = addmodpi( sx2, 0.0041); sy2 = addmodpi( sy2, 0.0031); tx2 = addmodpi( tx2, 0.0011 ); ty2 = addmodpi( ty2, 0.0023 ); basecol = addmod( basecol, 1.0, 0.007 ); rotate = { .a11 = cos(angle), .a12 = -sin(angle), .a21 = sin(angle), .a22 = cos(angle) }; Matrix zoom = { .a11 = sin(sx)/4.0 + 0.15, .a12 = 0, //atan(cos(sx2)), .a21 = 0, //atan(cos(sy2)), .a22 = cos(sy)/4.0 + 0.15 }; Vector translate = { .x1 = sin(tx) * LED_WIDTH, .x2 = sin(ty) * LED_HEIGHT }; for( int x = 0; x < LED_WIDTH; x++ ) { for( int y = 0; y < LED_HEIGHT; y++ ) { Vector c = add(multiply( multiply(rotate, zoom), { .x1 = x-rcx, .x2 = y-rcy } ), translate); //Vector c2 = add(multiply( multiply(zoom2, rotate2), { .x1 = x, .x2 = y } ), translate2); leds[XYsafe(x,y)] = CHSV((basecol+basefield(c.x1, c.x2))*255, 255, 255); //31+(sines(c2.x1-10, c2.x2-10)*224)); } } } }; class Static : public Effect { private: CRGB color; public: Static(CRGB col) { color = col; } void loop() { EVERY_N_SECONDS(1) { for ( int i = 0; i < LED_COUNT; i++) { leds[i] = color; } FastLED.show(); } } }; class Animation : public Effect { private: AnimationData *animation; int frame = 0; public: Animation(AnimationData *anim) { animation = anim; } void loop() { CRGB colors[animation->color_count]; int led_index = 0; for(int i=0; icolor_count; i++) colors[i] = CRGB(animation->colors[i]); for(int i=animation->offsets[frame]; ioffsets[frame+1]; i++) { if (animation->data[i]==255) { // Run-length encoded data for (int j=0; jdata[i+1]; j++) { if (frame==0 || animation->data[i+2]>0) { set(led_index, colors[animation->data[i+2]]); } led_index++; } i+=2; } else { if (frame==0 || animation->data[i]>0) { set(led_index, colors[animation->data[i]]); } led_index++; } } EVERY_N_MILLISECONDS(250) { frame = (frame + 1) % animation->frame_count; } } void set(int i, CRGB color) { setPixel(i % animation->w, i / animation->h, color); } }; struct EffectEntry { char* name; Effect* effect; };