Berry animation remove noise_animation (#24291)
This commit is contained in:
parent
f5d8ec43fc
commit
36424dd8e7
@ -167,7 +167,6 @@ Animation|Description
|
||||
`palette_gradient_animation`|Gradient patterns with palette colors
|
||||
`palette_meter_animation`|Meter/bar patterns
|
||||
`gradient_meter_animation`|VU meter with gradient and peak hold
|
||||
`noise_animation`|Perlin noise patterns
|
||||
`wave_animation`|Wave motion effects
|
||||
|
||||
## Documentation
|
||||
|
||||
@ -30,7 +30,6 @@ ParameterizedObject (base class with parameter management and playable interface
|
||||
│ ├── CometAnimation (moving comet with tail)
|
||||
│ ├── FireAnimation (realistic fire effect)
|
||||
│ ├── TwinkleAnimation (twinkling stars effect)
|
||||
│ ├── NoiseAnimation (Perlin noise patterns)
|
||||
│ ├── WaveAnimation (wave motion effects)
|
||||
│ └── RichPaletteAnimation (smooth palette transitions)
|
||||
├── SequenceManager (orchestrates animation sequences)
|
||||
@ -654,76 +653,6 @@ audio_meter.level = audio_level
|
||||
|
||||
**Factory**: `animation.gradient_meter_animation(engine)`
|
||||
|
||||
### NoiseAnimation
|
||||
|
||||
Creates pseudo-random noise patterns with configurable scale, speed, and fractal complexity. Perfect for organic, natural-looking effects like clouds, fire textures, or abstract patterns. Inherits from `Animation`.
|
||||
|
||||
| Parameter | Type | Default | Constraints | Description |
|
||||
|-----------|------|---------|-------------|-------------|
|
||||
| `color` | instance | nil | - | Color provider for noise mapping (nil = rainbow) |
|
||||
| `scale` | int | 50 | 1-255 | Noise scale/frequency (lower = larger patterns) |
|
||||
| `speed` | int | 30 | 0-255 | Animation speed (0 = static pattern) |
|
||||
| `octaves` | int | 1 | 1-4 | Number of noise octaves for fractal complexity |
|
||||
| `persistence` | int | 128 | 0-255 | How much each octave contributes to final pattern |
|
||||
| `seed` | int | 12345 | 0-65535 | Random seed for reproducible patterns |
|
||||
| *(inherits all Animation parameters)* | | | | |
|
||||
|
||||
#### Noise Characteristics
|
||||
|
||||
**Scale Effects:**
|
||||
- **Low scale (10-30)**: Large, flowing patterns
|
||||
- **Medium scale (40-80)**: Balanced detail and flow
|
||||
- **High scale (100-200)**: Fine, detailed textures
|
||||
|
||||
**Octave Effects:**
|
||||
- **1 octave**: Smooth, simple patterns
|
||||
- **2 octaves**: Added medium-frequency detail
|
||||
- **3+ octaves**: Complex, natural-looking textures
|
||||
|
||||
**Speed Effects:**
|
||||
- **Static (0)**: Fixed pattern for backgrounds
|
||||
- **Slow (10-40)**: Gentle, organic movement
|
||||
- **Fast (80-200)**: Dynamic, energetic patterns
|
||||
|
||||
#### Usage Examples
|
||||
|
||||
```berry
|
||||
# Rainbow noise with medium detail
|
||||
animation rainbow_noise = noise_animation(
|
||||
scale=60,
|
||||
speed=40,
|
||||
octaves=1
|
||||
)
|
||||
|
||||
# Blue fire texture with fractal detail
|
||||
color blue_fire = 0xFF0066FF
|
||||
animation blue_texture = noise_animation(
|
||||
color=blue_fire,
|
||||
scale=120,
|
||||
speed=60,
|
||||
octaves=3,
|
||||
persistence=100
|
||||
)
|
||||
|
||||
# Static cloud pattern
|
||||
animation cloud_pattern = noise_animation(
|
||||
color=white,
|
||||
scale=30,
|
||||
speed=0,
|
||||
octaves=2
|
||||
)
|
||||
```
|
||||
|
||||
#### Common Use Cases
|
||||
|
||||
- **Ambient Lighting**: Slow, low-scale noise for background ambiance
|
||||
- **Fire Effects**: Orange/red colors with medium scale and speed
|
||||
- **Water Effects**: Blue/cyan colors with flowing movement
|
||||
- **Cloud Simulation**: White/gray colors with large-scale patterns
|
||||
- **Abstract Art**: Rainbow colors with high detail and multiple octaves
|
||||
|
||||
|
||||
|
||||
### PulseAnimation
|
||||
|
||||
Creates a pulsing effect oscillating between min and max brightness. Inherits from `Animation`.
|
||||
@ -1230,7 +1159,6 @@ run gradient_wave
|
||||
- Each animation uses approximately 4 bytes per pixel for color storage
|
||||
- Fire animation includes additional flicker calculations
|
||||
- Gradient animation requires color interpolation calculations
|
||||
- Noise animation includes pseudo-random pattern generation
|
||||
- Consider strip length impact on transformation calculations
|
||||
|
||||
## Parameter Constraints
|
||||
|
||||
@ -1441,7 +1441,6 @@ Animation classes create visual effects on LED strips:
|
||||
| `fire_animation` | Realistic fire simulation |
|
||||
| `twinkle_animation` | Twinkling stars effect |
|
||||
| `gradient_animation` | Color gradient effects |
|
||||
| `noise_animation` | Perlin noise-based patterns |
|
||||
| `wave_animation` | Wave propagation effects |
|
||||
| `rich_palette_animation` | Palette-based color cycling |
|
||||
| `palette_wave_animation` | Wave patterns using palettes |
|
||||
|
||||
@ -145,8 +145,6 @@ import "animations/gradient" as gradient_animation
|
||||
register_to_animation(gradient_animation)
|
||||
import "animations/palette_meter" as palette_meter_animation
|
||||
register_to_animation(palette_meter_animation)
|
||||
import "animations/noise" as noise_animation
|
||||
register_to_animation(noise_animation)
|
||||
# import "animations/plasma" as plasma_animation
|
||||
# register_to_animation(plasma_animation)
|
||||
# import "animations/sparkle" as sparkle_animation
|
||||
|
||||
@ -1,288 +0,0 @@
|
||||
# Noise animation effect for Berry Animation Framework
|
||||
#
|
||||
# This animation creates pseudo-random noise patterns with configurable
|
||||
# scale, speed, and color mapping through palettes or single colors.
|
||||
|
||||
import "./core/param_encoder" as encode_constraints
|
||||
|
||||
#@ solidify:NoiseAnimation,weak
|
||||
class NoiseAnimation : animation.animation
|
||||
# Non-parameter instance variables only
|
||||
var current_colors # Array of current colors for each pixel
|
||||
var time_offset # Current time offset for animation
|
||||
var noise_table # Pre-computed noise values for performance
|
||||
|
||||
# Parameter definitions following new specification
|
||||
static var PARAMS = animation.enc_params({
|
||||
"color": {"default": nil},
|
||||
"scale": {"min": 1, "max": 255, "default": 50},
|
||||
"speed": {"min": 0, "max": 255, "default": 30},
|
||||
"octaves": {"min": 1, "max": 4, "default": 1},
|
||||
"persistence": {"min": 0, "max": 255, "default": 128},
|
||||
"seed": {"min": 0, "max": 65535, "default": 12345}
|
||||
})
|
||||
|
||||
# Initialize a new Noise animation
|
||||
def init(engine)
|
||||
# Call parent constructor with engine only
|
||||
super(self).init(engine)
|
||||
|
||||
# Initialize non-parameter instance variables only
|
||||
var strip_length = self.engine.strip_length
|
||||
self.current_colors = []
|
||||
self.current_colors.resize(strip_length)
|
||||
self.time_offset = 0
|
||||
|
||||
# Initialize colors to black
|
||||
var i = 0
|
||||
while i < strip_length
|
||||
self.current_colors[i] = 0xFF000000
|
||||
i += 1
|
||||
end
|
||||
|
||||
# Initialize noise table - will be done in start method
|
||||
self.noise_table = []
|
||||
|
||||
# Set default color if not set
|
||||
if self.color == nil
|
||||
var rainbow_provider = animation.rich_palette(engine)
|
||||
rainbow_provider.colors = animation.PALETTE_RAINBOW
|
||||
rainbow_provider.period = 5000
|
||||
rainbow_provider.transition_type = 1
|
||||
rainbow_provider.brightness = 255
|
||||
self.color = rainbow_provider
|
||||
end
|
||||
end
|
||||
|
||||
# Override start method for initialization
|
||||
def start(time_ms)
|
||||
# Call parent start first
|
||||
super(self).start(time_ms)
|
||||
|
||||
# Initialize noise table with current seed
|
||||
self._init_noise_table()
|
||||
|
||||
# Reset time offset
|
||||
self.time_offset = 0
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
# Initialize noise lookup table for performance
|
||||
def _init_noise_table()
|
||||
self.noise_table = []
|
||||
self.noise_table.resize(256)
|
||||
|
||||
# Generate pseudo-random values using seed
|
||||
var current_seed = self.seed
|
||||
var rng_state = current_seed
|
||||
var i = 0
|
||||
while i < 256
|
||||
rng_state = (rng_state * 1103515245 + 12345) & 0x7FFFFFFF
|
||||
self.noise_table[i] = rng_state % 256
|
||||
i += 1
|
||||
end
|
||||
end
|
||||
|
||||
# Override setmember to handle color conversion
|
||||
def setmember(name, value)
|
||||
if name == "color" && type(value) == "int"
|
||||
# Convert integer color to gradient palette from black to color
|
||||
var palette = bytes()
|
||||
palette.add(0x00, 1) # Position 0: black
|
||||
palette.add(0x00, 1) # R
|
||||
palette.add(0x00, 1) # G
|
||||
palette.add(0x00, 1) # B
|
||||
palette.add(0xFF, 1) # Position 255: full color
|
||||
palette.add((value >> 16) & 0xFF, 1) # R
|
||||
palette.add((value >> 8) & 0xFF, 1) # G
|
||||
palette.add(value & 0xFF, 1) # B
|
||||
|
||||
var gradient_provider = animation.rich_palette(self.engine)
|
||||
gradient_provider.colors = palette
|
||||
gradient_provider.period = 5000
|
||||
gradient_provider.transition_type = 1
|
||||
gradient_provider.brightness = 255
|
||||
|
||||
# Set the gradient provider instead of the integer
|
||||
super(self).setmember(name, gradient_provider)
|
||||
else
|
||||
# Use parent implementation for other parameters
|
||||
super(self).setmember(name, value)
|
||||
end
|
||||
end
|
||||
|
||||
# Handle parameter changes
|
||||
def on_param_changed(name, value)
|
||||
super(self).on_param_changed(name, value)
|
||||
if name == "seed"
|
||||
self._init_noise_table()
|
||||
end
|
||||
|
||||
# Update current_colors array size when strip length changes via engine
|
||||
var new_strip_length = self.engine.strip_length
|
||||
if size(self.current_colors) != new_strip_length
|
||||
self.current_colors.resize(new_strip_length)
|
||||
var i = size(self.current_colors)
|
||||
while i < new_strip_length
|
||||
self.current_colors[i] = 0xFF000000
|
||||
i += 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Simple noise function using lookup table
|
||||
def _noise_1d(x)
|
||||
var ix = int(x) & 255
|
||||
var fx = x - int(x)
|
||||
|
||||
# Get noise values at integer positions
|
||||
var a = self.noise_table[ix]
|
||||
var b = self.noise_table[(ix + 1) & 255]
|
||||
|
||||
# Linear interpolation using integer math
|
||||
var lerp_amount = tasmota.scale_uint(int(fx * 256), 0, 256, 0, 255)
|
||||
return tasmota.scale_uint(lerp_amount, 0, 255, a, b)
|
||||
end
|
||||
|
||||
# Fractal noise with multiple octaves
|
||||
def _fractal_noise(x, time_offset)
|
||||
var value = 0
|
||||
var amplitude = 255
|
||||
var current_scale = self.scale
|
||||
var current_octaves = self.octaves
|
||||
var current_persistence = self.persistence
|
||||
var frequency = current_scale
|
||||
var max_value = 0
|
||||
|
||||
var octave = 0
|
||||
while octave < current_octaves
|
||||
var sample_x = tasmota.scale_uint(x * frequency, 0, 255 * 255, 0, 255) + time_offset
|
||||
var noise_val = self._noise_1d(sample_x)
|
||||
|
||||
value += tasmota.scale_uint(noise_val, 0, 255, 0, amplitude)
|
||||
max_value += amplitude
|
||||
|
||||
amplitude = tasmota.scale_uint(amplitude, 0, 255, 0, current_persistence)
|
||||
frequency = frequency * 2
|
||||
if frequency > 255
|
||||
frequency = 255
|
||||
end
|
||||
|
||||
octave += 1
|
||||
end
|
||||
|
||||
# Normalize to 0-255 range
|
||||
if max_value > 0
|
||||
value = tasmota.scale_uint(value, 0, max_value, 0, 255)
|
||||
end
|
||||
|
||||
return value
|
||||
end
|
||||
|
||||
# Update animation state
|
||||
def update(time_ms)
|
||||
super(self).update(time_ms)
|
||||
|
||||
# Update time offset based on speed
|
||||
var current_speed = self.speed
|
||||
if current_speed > 0
|
||||
var elapsed = time_ms - self.start_time
|
||||
# Speed: 0-255 maps to 0-5 units per second
|
||||
var units_per_second = tasmota.scale_uint(current_speed, 0, 255, 0, 5)
|
||||
if units_per_second > 0
|
||||
self.time_offset = (elapsed * units_per_second / 1000) % 256
|
||||
end
|
||||
end
|
||||
|
||||
# Calculate noise colors
|
||||
self._calculate_noise(time_ms)
|
||||
end
|
||||
|
||||
# Calculate noise colors for all pixels
|
||||
def _calculate_noise(time_ms)
|
||||
var strip_length = self.engine.strip_length
|
||||
var current_color = self.color
|
||||
|
||||
var i = 0
|
||||
while i < strip_length
|
||||
# Calculate noise value for this pixel
|
||||
var noise_value = self._fractal_noise(i, self.time_offset)
|
||||
|
||||
# Get color from provider
|
||||
var color = 0xFF000000
|
||||
|
||||
# If the color is a provider that supports get_color_for_value, use it
|
||||
if animation.is_color_provider(current_color) && current_color.get_color_for_value != nil
|
||||
color = current_color.get_color_for_value(noise_value, 0)
|
||||
else
|
||||
# Use resolve_value with noise influence
|
||||
color = self.resolve_value(current_color, "color", time_ms + noise_value * 10)
|
||||
end
|
||||
|
||||
self.current_colors[i] = color
|
||||
i += 1
|
||||
end
|
||||
end
|
||||
|
||||
# Render noise to frame buffer
|
||||
def render(frame, time_ms, strip_length)
|
||||
var i = 0
|
||||
while i < strip_length
|
||||
if i < frame.width
|
||||
frame.set_pixel_color(i, self.current_colors[i])
|
||||
end
|
||||
i += 1
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
# Factory functions following new specification
|
||||
|
||||
# Create a rainbow noise animation preset
|
||||
def noise_rainbow(engine)
|
||||
var anim = animation.noise_animation(engine)
|
||||
# Set up rainbow color provider
|
||||
var rainbow_provider = animation.rich_palette(engine)
|
||||
rainbow_provider.colors = animation.PALETTE_RAINBOW
|
||||
rainbow_provider.period = 5000
|
||||
rainbow_provider.transition_type = 1
|
||||
rainbow_provider.brightness = 255
|
||||
anim.color = rainbow_provider
|
||||
anim.scale = 50
|
||||
anim.speed = 30
|
||||
anim.octaves = 1
|
||||
return anim
|
||||
end
|
||||
|
||||
# Create a single color noise animation preset
|
||||
def noise_single_color(engine)
|
||||
var anim = animation.noise_animation(engine)
|
||||
# Set up a simple white color - user can change it after creation
|
||||
anim.color = 0xFFFFFFFF
|
||||
anim.scale = 50
|
||||
anim.speed = 30
|
||||
anim.octaves = 1
|
||||
return anim
|
||||
end
|
||||
|
||||
# Create a fractal noise animation preset
|
||||
def noise_fractal(engine)
|
||||
var anim = animation.noise_animation(engine)
|
||||
# Set up rainbow color provider
|
||||
var rainbow_provider = animation.rich_palette(engine)
|
||||
rainbow_provider.colors = animation.PALETTE_RAINBOW
|
||||
rainbow_provider.period = 5000
|
||||
rainbow_provider.transition_type = 1
|
||||
rainbow_provider.brightness = 255
|
||||
anim.color = rainbow_provider
|
||||
anim.scale = 30
|
||||
anim.speed = 20
|
||||
anim.octaves = 3
|
||||
anim.persistence = 128
|
||||
return anim
|
||||
end
|
||||
|
||||
return {'noise_animation': NoiseAnimation, 'noise_rainbow': noise_rainbow, 'noise_single_color': noise_single_color, 'noise_fractal': noise_fractal}
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,232 +0,0 @@
|
||||
# Test suite for NoiseAnimation
|
||||
#
|
||||
# This test verifies that the NoiseAnimation works correctly
|
||||
# with different parameters and color providers.
|
||||
|
||||
import animation
|
||||
import string
|
||||
|
||||
# Test basic NoiseAnimation creation and functionality
|
||||
def test_noise_animation_basic()
|
||||
print("Testing basic NoiseAnimation...")
|
||||
|
||||
# Create LED strip and engine
|
||||
var strip = global.Leds(10)
|
||||
var engine = animation.create_engine(strip)
|
||||
|
||||
# Test with default parameters
|
||||
var noise_anim = animation.noise_animation(engine)
|
||||
|
||||
assert(noise_anim != nil, "NoiseAnimation should be created")
|
||||
assert(noise_anim.scale == 50, "Default scale should be 50")
|
||||
assert(noise_anim.speed == 30, "Default speed should be 30")
|
||||
assert(noise_anim.octaves == 1, "Default octaves should be 1")
|
||||
assert(noise_anim.is_running == false, "Animation should not be running initially")
|
||||
|
||||
print("✓ Basic NoiseAnimation test passed")
|
||||
end
|
||||
|
||||
# Test NoiseAnimation with custom parameters
|
||||
def test_noise_animation_custom()
|
||||
print("Testing NoiseAnimation with custom parameters...")
|
||||
|
||||
# Create LED strip and engine
|
||||
var strip = global.Leds(20)
|
||||
var engine = animation.create_engine(strip)
|
||||
|
||||
# Test with custom parameters
|
||||
var noise_anim = animation.noise_animation(engine)
|
||||
noise_anim.color = 0xFF00FF00
|
||||
noise_anim.scale = 100
|
||||
noise_anim.speed = 80
|
||||
noise_anim.octaves = 2
|
||||
noise_anim.persistence = 200
|
||||
noise_anim.seed = 12345
|
||||
noise_anim.priority = 15
|
||||
noise_anim.duration = 5000
|
||||
noise_anim.loop = false
|
||||
|
||||
assert(noise_anim.scale == 100, "Custom scale should be 100")
|
||||
assert(noise_anim.speed == 80, "Custom speed should be 80")
|
||||
assert(noise_anim.octaves == 2, "Custom octaves should be 2")
|
||||
assert(noise_anim.persistence == 200, "Custom persistence should be 200")
|
||||
assert(noise_anim.seed == 12345, "Custom seed should be 12345")
|
||||
assert(noise_anim.priority == 15, "Custom priority should be 15")
|
||||
assert(noise_anim.duration == 5000, "Custom duration should be 5000")
|
||||
assert(noise_anim.loop == false, "Custom loop should be false")
|
||||
|
||||
print("✓ Custom NoiseAnimation test passed")
|
||||
end
|
||||
|
||||
# Test NoiseAnimation parameter changes
|
||||
def test_noise_animation_parameters()
|
||||
print("Testing NoiseAnimation parameter changes...")
|
||||
|
||||
# Create LED strip and engine
|
||||
var strip = global.Leds(15)
|
||||
var engine = animation.create_engine(strip)
|
||||
|
||||
var noise_anim = animation.noise_animation(engine)
|
||||
|
||||
# Test parameter changes via virtual member assignment
|
||||
noise_anim.scale = 75
|
||||
assert(noise_anim.scale == 75, "Scale should be updated to 75")
|
||||
|
||||
noise_anim.speed = 120
|
||||
assert(noise_anim.speed == 120, "Speed should be updated to 120")
|
||||
|
||||
noise_anim.octaves = 3
|
||||
assert(noise_anim.octaves == 3, "Octaves should be updated to 3")
|
||||
|
||||
# Test that current_colors array adapts to engine strip length
|
||||
var initial_size = size(noise_anim.current_colors)
|
||||
assert(initial_size == 15, "Current colors array should match engine strip length")
|
||||
|
||||
print("✓ NoiseAnimation parameter test passed")
|
||||
end
|
||||
|
||||
# Test NoiseAnimation update and render
|
||||
def test_noise_animation_update_render()
|
||||
print("Testing NoiseAnimation update and render...")
|
||||
|
||||
# Create LED strip and engine
|
||||
var strip = global.Leds(10)
|
||||
var engine = animation.create_engine(strip)
|
||||
|
||||
var noise_anim = animation.noise_animation(engine)
|
||||
noise_anim.color = 0xFFFF0000
|
||||
noise_anim.scale = 60
|
||||
noise_anim.speed = 40
|
||||
|
||||
var frame = animation.frame_buffer(10)
|
||||
|
||||
# Start animation
|
||||
# Note: When testing animations directly (not through engine_proxy), we must set start_time manually
|
||||
noise_anim.start_time = 1000 # Set start_time manually for direct testing
|
||||
noise_anim.start(1000)
|
||||
assert(noise_anim.is_running == true, "Animation should be running after start")
|
||||
|
||||
# Test update
|
||||
noise_anim.update(1500)
|
||||
assert(noise_anim.is_running == true, "Animation should still be running after update")
|
||||
|
||||
# Test render
|
||||
var result = noise_anim.render(frame, 1500, engine.strip_length)
|
||||
assert(result == true, "Render should return true for running animation")
|
||||
|
||||
# Check that colors were set (should not all be black)
|
||||
var has_non_black = false
|
||||
var i = 0
|
||||
while i < frame.width
|
||||
if frame.get_pixel_color(i) != 0xFF000000
|
||||
has_non_black = true
|
||||
break
|
||||
end
|
||||
i += 1
|
||||
end
|
||||
assert(has_non_black == true, "Frame should have non-black pixels after render")
|
||||
|
||||
print("✓ NoiseAnimation update/render test passed")
|
||||
end
|
||||
|
||||
# Test global constructor functions
|
||||
def test_noise_constructors()
|
||||
print("Testing noise constructor functions...")
|
||||
|
||||
# Create LED strip and engine
|
||||
var strip = global.Leds(15)
|
||||
var engine = animation.create_engine(strip)
|
||||
|
||||
# Test noise_rainbow
|
||||
var rainbow_noise = animation.noise_rainbow(engine)
|
||||
assert(rainbow_noise != nil, "noise_rainbow should create animation")
|
||||
assert(rainbow_noise.scale == 50, "Rainbow noise should have correct scale")
|
||||
assert(rainbow_noise.speed == 30, "Rainbow noise should have correct speed")
|
||||
assert(rainbow_noise.octaves == 1, "Rainbow noise should have correct octaves")
|
||||
|
||||
# Test noise_single_color
|
||||
var single_noise = animation.noise_single_color(engine)
|
||||
assert(single_noise != nil, "noise_single_color should create animation")
|
||||
assert(single_noise.scale == 50, "Single color noise should have correct scale")
|
||||
assert(single_noise.speed == 30, "Single color noise should have correct speed")
|
||||
assert(single_noise.color == 0xFFFFFFFF, "Single color noise should have white color")
|
||||
|
||||
# Test noise_fractal
|
||||
var fractal_noise = animation.noise_fractal(engine)
|
||||
assert(fractal_noise != nil, "noise_fractal should create animation")
|
||||
assert(fractal_noise.scale == 30, "Fractal noise should have correct scale")
|
||||
assert(fractal_noise.octaves == 3, "Fractal noise should have correct octaves")
|
||||
|
||||
print("✓ Noise constructor functions test passed")
|
||||
end
|
||||
|
||||
# Test NoiseAnimation string representation
|
||||
def test_noise_tostring()
|
||||
print("Testing NoiseAnimation string representation...")
|
||||
|
||||
# Create LED strip and engine
|
||||
var strip = global.Leds(12)
|
||||
var engine = animation.create_engine(strip)
|
||||
|
||||
var noise_anim = animation.noise_animation(engine)
|
||||
noise_anim.scale = 75
|
||||
noise_anim.speed = 45
|
||||
noise_anim.octaves = 2
|
||||
noise_anim.persistence = 150
|
||||
|
||||
var str_repr = str(noise_anim)
|
||||
|
||||
assert(type(str_repr) == "string", "String representation should be a string")
|
||||
|
||||
print("✓ NoiseAnimation string representation test passed")
|
||||
end
|
||||
|
||||
# Test integer color conversion to gradient
|
||||
def test_noise_integer_color_conversion()
|
||||
print("Testing NoiseAnimation integer color conversion...")
|
||||
|
||||
# Create LED strip and engine
|
||||
var strip = global.Leds(5)
|
||||
var engine = animation.create_engine(strip)
|
||||
|
||||
var noise_anim = animation.noise_animation(engine)
|
||||
|
||||
# Set an integer color - should be converted to gradient provider
|
||||
noise_anim.color = 0xFFFF0000 # Red
|
||||
|
||||
# Check the raw parameter value (should be a color provider)
|
||||
var raw_color = noise_anim.get_param("color")
|
||||
|
||||
# Test that the raw parameter is a color provider (the conversion worked)
|
||||
assert(animation.is_color_provider(raw_color), "Integer color should be converted to color provider")
|
||||
|
||||
print("✓ NoiseAnimation integer color conversion test passed")
|
||||
end
|
||||
|
||||
# Run all tests
|
||||
def run_noise_animation_tests()
|
||||
print("=== NoiseAnimation Tests ===")
|
||||
|
||||
try
|
||||
test_noise_animation_basic()
|
||||
test_noise_animation_custom()
|
||||
test_noise_animation_parameters()
|
||||
test_noise_animation_update_render()
|
||||
test_noise_constructors()
|
||||
test_noise_tostring()
|
||||
test_noise_integer_color_conversion()
|
||||
|
||||
print("=== All NoiseAnimation tests passed! ===")
|
||||
return true
|
||||
except .. as e, msg
|
||||
print(f"Test failed: {e} - {msg}")
|
||||
raise "test_failed"
|
||||
end
|
||||
end
|
||||
|
||||
# Export the test function
|
||||
animation.run_noise_animation_tests = run_noise_animation_tests
|
||||
|
||||
run_noise_animation_tests()
|
||||
|
||||
return run_noise_animation_tests
|
||||
@ -75,9 +75,9 @@ def run_all_tests()
|
||||
"lib/libesp32/berry_animation/src/tests/twinkle_animation_test.be",
|
||||
"lib/libesp32/berry_animation/src/tests/crenel_position_animation_test.be",
|
||||
"lib/libesp32/berry_animation/src/tests/beacon_animation_test.be",
|
||||
"lib/libesp32/berry_animation/src/tests/test_beacon_direction.be",
|
||||
"lib/libesp32/berry_animation/src/tests/gradient_animation_test.be",
|
||||
"lib/libesp32/berry_animation/src/tests/palette_meter_animation_test.be",
|
||||
"lib/libesp32/berry_animation/src/tests/noise_animation_test.be",
|
||||
# "lib/libesp32/berry_animation/src/tests/plasma_animation_test.be",
|
||||
# "lib/libesp32/berry_animation/src/tests/sparkle_animation_test.be",
|
||||
"lib/libesp32/berry_animation/src/tests/wave_animation_test.be",
|
||||
|
||||
138
lib/libesp32/berry_animation/src/tests/test_beacon_direction.be
Normal file
138
lib/libesp32/berry_animation/src/tests/test_beacon_direction.be
Normal file
@ -0,0 +1,138 @@
|
||||
# Test for beacon animation right_edge parameter
|
||||
# Tests that right_edge=1 positions the beacon using pos as the right edge of the beacon
|
||||
|
||||
import animation
|
||||
import global
|
||||
|
||||
# Test counter
|
||||
var test_count = 0
|
||||
var passed_count = 0
|
||||
|
||||
# Create LED strip and engine for testing
|
||||
var strip = global.Leds(10) # Use built-in LED strip for testing
|
||||
var engine = animation.create_engine(strip)
|
||||
|
||||
def test_assert(condition, message)
|
||||
test_count += 1
|
||||
if condition
|
||||
passed_count += 1
|
||||
print(f"✓ Test {test_count}: {message}")
|
||||
else
|
||||
print(f"✗ Test {test_count}: {message}")
|
||||
end
|
||||
end
|
||||
|
||||
def run_tests()
|
||||
print("Running Beacon Animation right_edge Tests...")
|
||||
print("==================================================")
|
||||
|
||||
var strip_length = 10
|
||||
var frame = animation.frame_buffer(strip_length)
|
||||
|
||||
# Test 1: right_edge=0 (default, left edge), pos=0, beacon_size=1
|
||||
# Should show 1 pixel at position 0 (left edge)
|
||||
var beacon1 = animation.beacon_animation(engine)
|
||||
beacon1.color = 0xFFFF0000 # Red
|
||||
beacon1.back_color = 0xFF000000 # Black
|
||||
beacon1.pos = 0
|
||||
beacon1.beacon_size = 1
|
||||
beacon1.slew_size = 0
|
||||
beacon1.right_edge = 0
|
||||
beacon1.start()
|
||||
|
||||
frame.fill_pixels(frame.pixels, 0xFF000000) # Clear to black
|
||||
beacon1.render(frame, 0, strip_length)
|
||||
|
||||
# Check pixel 0 is red, others are black
|
||||
test_assert(frame.get_pixel_color(0) == 0xFFFF0000, "right_edge=0, pos=0: pixel 0 is red")
|
||||
test_assert(frame.get_pixel_color(1) == 0xFF000000, "right_edge=0, pos=0: pixel 1 is black")
|
||||
test_assert(frame.get_pixel_color(9) == 0xFF000000, "right_edge=0, pos=0: pixel 9 is black")
|
||||
|
||||
# Test 2: right_edge=1 (right edge), pos=0, beacon_size=1
|
||||
# With right_edge=1: effective_pos = pos - beacon_size + 1 = 0 - 1 + 1 = 0
|
||||
# So pixel 0 should be lit
|
||||
var beacon2 = animation.beacon_animation(engine)
|
||||
beacon2.color = 0xFF00FF00 # Green
|
||||
beacon2.back_color = 0xFF000000 # Black
|
||||
beacon2.pos = 0
|
||||
beacon2.beacon_size = 1
|
||||
beacon2.slew_size = 0
|
||||
beacon2.right_edge = 1
|
||||
beacon2.start()
|
||||
|
||||
frame.fill_pixels(frame.pixels, 0xFF000000) # Clear to black
|
||||
beacon2.render(frame, 0, strip_length)
|
||||
|
||||
# Check pixel 0 is green (right edge of beacon at pos=0)
|
||||
test_assert(frame.get_pixel_color(0) == 0xFF00FF00, "right_edge=1, pos=0: pixel 0 is green")
|
||||
test_assert(frame.get_pixel_color(1) == 0xFF000000, "right_edge=1, pos=0: pixel 1 is black")
|
||||
|
||||
# Test 3: right_edge=1, pos=5, beacon_size=3
|
||||
# With right_edge=1: effective_pos = pos - beacon_size + 1 = 5 - 3 + 1 = 3
|
||||
# So pixels 3,4,5 should be lit (beacon from 3 to 5, with right edge at 5)
|
||||
var beacon3 = animation.beacon_animation(engine)
|
||||
beacon3.color = 0xFF0000FF # Blue
|
||||
beacon3.back_color = 0xFF000000 # Black
|
||||
beacon3.pos = 5
|
||||
beacon3.beacon_size = 3
|
||||
beacon3.slew_size = 0
|
||||
beacon3.right_edge = 1
|
||||
beacon3.start()
|
||||
|
||||
frame.fill_pixels(frame.pixels, 0xFF000000) # Clear to black
|
||||
beacon3.render(frame, 0, strip_length)
|
||||
|
||||
test_assert(frame.get_pixel_color(2) == 0xFF000000, "right_edge=1, pos=5, size=3: pixel 2 is black")
|
||||
test_assert(frame.get_pixel_color(3) == 0xFF0000FF, "right_edge=1, pos=5, size=3: pixel 3 is blue")
|
||||
test_assert(frame.get_pixel_color(4) == 0xFF0000FF, "right_edge=1, pos=5, size=3: pixel 4 is blue")
|
||||
test_assert(frame.get_pixel_color(5) == 0xFF0000FF, "right_edge=1, pos=5, size=3: pixel 5 is blue")
|
||||
test_assert(frame.get_pixel_color(6) == 0xFF000000, "right_edge=1, pos=5, size=3: pixel 6 is black")
|
||||
|
||||
# Test 4: right_edge=0, pos=2, beacon_size=3 (same params, different right_edge)
|
||||
# Should show pixels 2,3,4 lit
|
||||
var beacon4 = animation.beacon_animation(engine)
|
||||
beacon4.color = 0xFFFFFF00 # Yellow
|
||||
beacon4.back_color = 0xFF000000 # Black
|
||||
beacon4.pos = 2
|
||||
beacon4.beacon_size = 3
|
||||
beacon4.slew_size = 0
|
||||
beacon4.right_edge = 0
|
||||
beacon4.start()
|
||||
|
||||
frame.fill_pixels(frame.pixels, 0xFF000000) # Clear to black
|
||||
beacon4.render(frame, 0, strip_length)
|
||||
|
||||
test_assert(frame.get_pixel_color(1) == 0xFF000000, "right_edge=0, pos=2, size=3: pixel 1 is black")
|
||||
test_assert(frame.get_pixel_color(2) == 0xFFFFFF00, "right_edge=0, pos=2, size=3: pixel 2 is yellow")
|
||||
test_assert(frame.get_pixel_color(3) == 0xFFFFFF00, "right_edge=0, pos=2, size=3: pixel 3 is yellow")
|
||||
test_assert(frame.get_pixel_color(4) == 0xFFFFFF00, "right_edge=0, pos=2, size=3: pixel 4 is yellow")
|
||||
test_assert(frame.get_pixel_color(5) == 0xFF000000, "right_edge=0, pos=2, size=3: pixel 5 is black")
|
||||
|
||||
# Test 5: Default right_edge should be 0
|
||||
var beacon5 = animation.beacon_animation(engine)
|
||||
test_assert(beacon5.right_edge == 0, "Default right_edge is 0")
|
||||
|
||||
# Test 6: Invalid right_edge value should be rejected
|
||||
try
|
||||
beacon5.right_edge = 2
|
||||
test_assert(false, "Invalid right_edge value should be rejected")
|
||||
except "value_error"
|
||||
test_assert(true, "Invalid right_edge value properly rejected")
|
||||
end
|
||||
|
||||
print("==================================================")
|
||||
print(f"Tests completed: {passed_count}/{test_count} passed")
|
||||
|
||||
if passed_count == test_count
|
||||
print("🎉 All tests passed!")
|
||||
return true
|
||||
else
|
||||
print(f"❌ {test_count - passed_count} tests failed")
|
||||
raise "test_failed"
|
||||
end
|
||||
end
|
||||
|
||||
# Run the tests
|
||||
var success = run_tests()
|
||||
|
||||
return success
|
||||
Loading…
Reference in New Issue
Block a user