Lots of changes:
* More animations with generalized code to display them. * The hostname will now include a unique id of the ESP. * Effect can now be restricted to a smaller "window". * Clock is now BigClock, SmallClock is now Clock. * Clock shows the time as well as the sinematrix effect. Closes #8. * If the loop takes too long too often, the ESP will automatically be rebooted. Closes #12. * The text drawing methods are now much more generalized. #5.
This commit is contained in:
150
effects.h
150
effects.h
@ -1,21 +1,33 @@
|
||||
class Effect {
|
||||
protected:
|
||||
Window window = {0, 0, LED_WIDTH, LED_HEIGHT}; // Use a full screen window per default.
|
||||
public:
|
||||
virtual void loop() {};
|
||||
virtual void loop() = 0;
|
||||
boolean supports_window = false;
|
||||
void setWindow(Window win) {
|
||||
window = win;
|
||||
};
|
||||
};
|
||||
|
||||
struct EffectEntry {
|
||||
char* name;
|
||||
Effect* effect;
|
||||
};
|
||||
|
||||
class Bell : public Effect {
|
||||
private:
|
||||
|
||||
|
||||
CRGB color_on = CRGB(0xFFFF00);
|
||||
CRGB color_off= CRGB(0x000000);
|
||||
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;
|
||||
Serial.println("This is Bell.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -23,10 +35,10 @@ class Bell : public Effect {
|
||||
EVERY_N_MILLISECONDS(300) {
|
||||
invert = !invert;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class Clock : public Effect {
|
||||
class BigClock : public Effect {
|
||||
private:
|
||||
CRGB color_h = CRGB(0xFF0000);
|
||||
CRGB color_m = CRGB(0x00FF00);
|
||||
@ -59,7 +71,7 @@ class Clock : public Effect {
|
||||
}
|
||||
}
|
||||
public:
|
||||
Clock() {}
|
||||
BigClock() {}
|
||||
void loop() {
|
||||
clear();
|
||||
drawNumber(ntpClient.getHours(), 0, 0, color_h);
|
||||
@ -72,27 +84,44 @@ class Clock : public Effect {
|
||||
}
|
||||
};
|
||||
|
||||
class SmallClock : public Effect {
|
||||
class Clock : public Effect {
|
||||
private:
|
||||
CRGB color_h = CRGB(0xFF0000);
|
||||
CRGB color_m = CRGB(0x00FF00);
|
||||
CRGB color_colon = CRGB(0xFFFF00);
|
||||
Effect* secondary_effect = 0;
|
||||
Window window = {0, LED_HEIGHT - 5, LED_WIDTH, 5};
|
||||
Window secondary_window = {0, 0, LED_WIDTH, LED_HEIGHT - 6};
|
||||
long secondary_effect_started_at = 0;
|
||||
|
||||
public:
|
||||
SmallClock() {}
|
||||
EffectEntry* effects;
|
||||
void setEffects(EffectEntry* e) {
|
||||
effects = e;
|
||||
}
|
||||
Clock() {}
|
||||
|
||||
void loop() {
|
||||
clear();
|
||||
clear(window);
|
||||
int h = ntpClient.getHours();
|
||||
drawDigit(numbers3x5, 3, 5, 0, 11, h/10, color_h);
|
||||
drawDigit(numbers3x5, 3, 5, 4, 11, h%10, color_h);
|
||||
drawDigit(window, numbers3x5, 3, 5, 0, 0, h / 10, color_h);
|
||||
drawDigit(window, numbers3x5, 3, 5, 4, 0, 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);
|
||||
drawDigit(window, numbers3x5, 3, 5, 9, 0, m / 10, color_m);
|
||||
drawDigit(window, numbers3x5, 3, 5, 13, 0, m % 10, color_m);
|
||||
if (ntpClient.getSeconds() & 1) {
|
||||
leds[XYsafe(7, 12)] = color_colon;
|
||||
leds[XYsafe(7, 14)] = color_colon;
|
||||
setPixel(window, 7, 1, color_colon);
|
||||
setPixel(window, 7, 3, color_colon);
|
||||
}
|
||||
|
||||
// Change effect?
|
||||
if (secondary_effect == 0 || secondary_effect_started_at == 0 || millis() - secondary_effect_started_at > EFFECT_CYCLE_TIME) {
|
||||
secondary_effect = effects[0].effect;
|
||||
secondary_effect_started_at = millis();
|
||||
secondary_effect->setWindow(secondary_window);
|
||||
}
|
||||
|
||||
secondary_effect->loop();
|
||||
}
|
||||
};
|
||||
|
||||
@ -114,14 +143,15 @@ class Sinematrix3 : public Effect {
|
||||
double tx2 = 0;
|
||||
double ty2 = 0;
|
||||
double basecol = 0;
|
||||
double fx = 1.0/(LED_WIDTH/PI);
|
||||
double fy = 1.0/(LED_HEIGHT/PI);
|
||||
double fx = 1.0 / (LED_WIDTH / PI);
|
||||
double fy = 1.0 / (LED_HEIGHT / PI);
|
||||
Matrix rotate;
|
||||
|
||||
public:
|
||||
boolean supports_window = true;
|
||||
Sinematrix3() {}
|
||||
void loop() {
|
||||
pangle = addmodpi( pangle, 0.0133 + (angle/256) );
|
||||
pangle = addmodpi( pangle, 0.0133 + (angle / 256) );
|
||||
angle = cos(pangle) * PI;
|
||||
sx = addmodpi( sx, 0.00673 );
|
||||
sy = addmodpi( sy, 0.00437 );
|
||||
@ -129,15 +159,15 @@ class Sinematrix3 : public Effect {
|
||||
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);
|
||||
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),
|
||||
@ -145,21 +175,22 @@ class Sinematrix3 : public Effect {
|
||||
.a22 = cos(angle)
|
||||
};
|
||||
Matrix zoom = {
|
||||
.a11 = sin(sx)/4.0 + 0.15,
|
||||
.a11 = sin(sx) / 4.0 + 0.15,
|
||||
.a12 = 0, //atan(cos(sx2)),
|
||||
.a21 = 0, //atan(cos(sy2)),
|
||||
.a22 = cos(sy)/4.0 + 0.15
|
||||
.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);
|
||||
|
||||
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));
|
||||
setPixel(window, x, y, CHSV((basecol + basefield(c.x1, c.x2)) * 255, 255, 255));
|
||||
//leds[XYsafe(x,y)] = CHSV((basecol+basefield(c.x1, c.x2))*255, 255, 255); //31+(sines(c2.x1-10, c2.x2-10)*224));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -172,12 +203,10 @@ class Static : public Effect {
|
||||
Static(CRGB col) {
|
||||
color = col;
|
||||
}
|
||||
boolean supports_window = true;
|
||||
void loop() {
|
||||
EVERY_N_SECONDS(1) {
|
||||
for ( int i = 0; i < LED_COUNT; i++) {
|
||||
leds[i] = color;
|
||||
}
|
||||
FastLED.show();
|
||||
clear(window, color);
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -186,40 +215,59 @@ class Animation : public Effect {
|
||||
private:
|
||||
AnimationData *animation;
|
||||
int frame = 0;
|
||||
CRGB background_color;
|
||||
int xOffset, yOffset;
|
||||
long frameSince = 0;
|
||||
public:
|
||||
Animation(AnimationData *anim) {
|
||||
Animation(anim, CRGB(0), 0, 0);
|
||||
}
|
||||
Animation(AnimationData *anim, CRGB background_color) {
|
||||
Animation(anim, background_color, 0, 0);
|
||||
}
|
||||
Animation(AnimationData *anim, CRGB bg_color, int x, int y) {
|
||||
animation = anim;
|
||||
background_color = bg_color;
|
||||
xOffset = x;
|
||||
yOffset = y;
|
||||
}
|
||||
void loop() {
|
||||
Serial.printf("Animation.loop. Animation is %p.", (void *)animation);
|
||||
CRGB colors[animation->color_count];
|
||||
int led_index = 0;
|
||||
for(int i=0; i<animation->color_count; i++) colors[i] = CRGB(animation->colors[i]);
|
||||
for(int i=animation->offsets[frame]; i<animation->offsets[frame+1]; i++) {
|
||||
if (animation->data[i]==255) { // Run-length encoded data
|
||||
for (int j=0; j<animation->data[i+1]; j++) {
|
||||
if (frame==0 || animation->data[i+2]>0) {
|
||||
set(led_index, colors[animation->data[i+2]]);
|
||||
for (int i = 0; i < animation->color_count; i++) colors[i] = CRGB(animation->colors[i]);
|
||||
for (int i = animation->offsets[frame]; i < animation->offsets[frame + 1]; i++) {
|
||||
if (animation->data[i] == 255) { // Run-length encoded data
|
||||
uint8_t color = animation->data[i + 2];
|
||||
for (int j = 0; j < animation->data[i + 1]; j++) {
|
||||
if (color > 1) {
|
||||
set(led_index, colors[animation->data[i + 2]]);
|
||||
} else if (color==1) {
|
||||
set(led_index, background_color);
|
||||
}
|
||||
led_index++;
|
||||
}
|
||||
i+=2;
|
||||
i += 2;
|
||||
} else {
|
||||
if (frame==0 || animation->data[i]>0) {
|
||||
uint8_t color = animation->data[i];
|
||||
if (color > 1) {
|
||||
set(led_index, colors[animation->data[i]]);
|
||||
} else if (color == 1) {
|
||||
set(led_index, background_color);
|
||||
}
|
||||
led_index++;
|
||||
}
|
||||
}
|
||||
EVERY_N_MILLISECONDS(250) {
|
||||
if (frameSince == 0 || frameSince + frameDelay(animation, frame) < millis() || frameSince > millis()) {
|
||||
frame = (frame + 1) % animation->frame_count;
|
||||
frameSince = millis();
|
||||
}
|
||||
}
|
||||
void set(int i, CRGB color) {
|
||||
setPixel(i % animation->w, i / animation->h, color);
|
||||
setPixel(xOffset + (i % animation->w), yOffset + (i / animation->h), color);
|
||||
}
|
||||
uint16_t frameDelay(AnimationData* animation, int frame) {
|
||||
if (animation->individual_delays) return animation->delays[frame];
|
||||
return animation->delays[0];
|
||||
}
|
||||
};
|
||||
|
||||
struct EffectEntry {
|
||||
char* name;
|
||||
Effect* effect;
|
||||
};
|
||||
|
Reference in New Issue
Block a user