From 2d2cb84e7bf8a0a5f9096538027a1d047da023ab Mon Sep 17 00:00:00 2001 From: Neradoc Date: Mon, 18 Jul 2022 02:29:11 +0200 Subject: [PATCH] Animations using after_draw() don't work properly The Sparkle animation uses `after_draw` to setup the pixels currently being sparkled for the next frame, assuming `show()` will not be called until then. It also calls `show()` itself first to show the changes made in `draw()`. The problem is that `animate()` already calls `show()` after calling draw and after_draw. So the frame where the sparkle should show is actually skipped and only briefly appears instead of staying for a frame according to the speed parameter. The refactor from PR #23 changed the protocol where animations should no longer call `show()` themselves. We can't change `after_draw` to be called after the call to show() in animate(), because it will break on animation groups using the same strip. If another animation triggers a show() sooner, it will show the next frame of the sparkle prematurely. It also makes the protocol less predictable. I have used `animate(False)`, followed by setting a pixel an calling `show()` for example to force the color of a single or a few pixels without going through the hassle of creating pixelmaps or groups (and also to simply make it look like it's superimposed over the animation). So the solution would be to drop `after_draw` and instead memorize the previous list of pixels and set them back in the next draw. --- adafruit_led_animation/animation/__init__.py | 1 - adafruit_led_animation/animation/rainbowsparkle.py | 4 ++-- adafruit_led_animation/animation/sparkle.py | 9 +++------ adafruit_led_animation/animation/sparklepulse.py | 4 +--- 4 files changed, 6 insertions(+), 12 deletions(-) diff --git a/adafruit_led_animation/animation/__init__.py b/adafruit_led_animation/animation/__init__.py index e870b5f..ab4b834 100644 --- a/adafruit_led_animation/animation/__init__.py +++ b/adafruit_led_animation/animation/__init__.py @@ -83,7 +83,6 @@ def animate(self, show=True): for anim in self._peers: anim.draw_count += 1 anim.draw() - anim.after_draw() if show: for anim in self._peers: diff --git a/adafruit_led_animation/animation/rainbowsparkle.py b/adafruit_led_animation/animation/rainbowsparkle.py index 0be7a71..8538fb8 100644 --- a/adafruit_led_animation/animation/rainbowsparkle.py +++ b/adafruit_led_animation/animation/rainbowsparkle.py @@ -89,8 +89,8 @@ def generate_rainbow(self): int(self._background_brightness * color[2]), ) - def after_draw(self): - self.show() + def draw(self): + super().draw() pixels = [ random.randint(0, len(self.pixel_object) - 1) for n in range(self._num_sparkles) diff --git a/adafruit_led_animation/animation/sparkle.py b/adafruit_led_animation/animation/sparkle.py index cbe8a80..ee2a326 100644 --- a/adafruit_led_animation/animation/sparkle.py +++ b/adafruit_led_animation/animation/sparkle.py @@ -83,13 +83,10 @@ def _random_in_mask(self): return self._mask[random.randint(0, (len(self._mask) - 1))] def draw(self): - self._pixels = [self._random_in_mask() for _ in range(self._num_sparkles)] - for pixel in self._pixels: - self.pixel_object[pixel] = self._sparkle_color - - def after_draw(self): - self.show() for pixel in self._pixels: self.pixel_object[pixel % self._num_pixels] = self._half_color if (pixel + 1) % self._num_pixels in self._mask: self.pixel_object[(pixel + 1) % self._num_pixels] = self._dim_color + self._pixels = [self._random_in_mask() for _ in range(self._num_sparkles)] + for pixel in self._pixels: + self.pixel_object[pixel] = self._sparkle_color diff --git a/adafruit_led_animation/animation/sparklepulse.py b/adafruit_led_animation/animation/sparklepulse.py index efb0d1d..cd469e2 100644 --- a/adafruit_led_animation/animation/sparklepulse.py +++ b/adafruit_led_animation/animation/sparklepulse.py @@ -64,10 +64,8 @@ def __init__( def _set_color(self, color): self._color = color + super()._set_color(color) def draw(self): self._sparkle_color = next(self._generator) super().draw() - - def after_draw(self): - self.show()