-
Notifications
You must be signed in to change notification settings - Fork 3
/
led.py
142 lines (99 loc) · 3.44 KB
/
led.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
from copy import deepcopy
import time
from sunrise import get_brightness_level
from options import led_options
try:
import unicornhathd as hat
print('Unicorn HAT HD module found.')
except ImportError:
from unicorn_hat_sim import unicornhathd as hat
print('Unicorn HAT HD simulator module found.')
width, height = hat.get_shape()
buffer = []
old_buffer = []
def map_coords(x, y):
return (width - x - 1, y)
def setup():
global buffer, old_buffer
clear()
old_buffer = deepcopy(buffer)
def draw_frame(frame, x, y, filters=[]):
for y2 in range(len(frame)):
for x2 in range(len(frame[y2])):
# Check for out of bounds
xx2, yy2 = x + x2, y + y2
if not in_bounds(xx2, yy2):
continue
old_px = buffer[yy2][xx2]
in_rgb = apply_filters(frame[y2][x2][:3], filters)
in_alpha = frame[y2][x2][3]
if in_alpha == 0:
continue
elif in_alpha == 255:
add_px = in_rgb
else:
in_alpha = float(in_alpha) / 255
add_px = [int(val * in_alpha) for val in in_rgb]
new_px = [old + new for old, new in zip(old_px, add_px)]
new_px = [min(max(val, 0), 255) for val in new_px]
buffer[yy2][xx2] = new_px
# hat.set_pixel(*map_coords(xx2, yy2), *(new_px))
def apply_filters(in_rgb, filters):
for blend_mode, f_rgb in filters:
if blend_mode == 'multiply':
in_rgb = [int(x * (y / 255)) for x, y in zip(in_rgb, f_rgb)]
return in_rgb
def set_px(x, y, color, filters=[]):
if in_bounds(x, y):
buffer[y][x] = apply_filters(color, filters)
def in_bounds(x, y):
return not (x < 0 or x >= width or y < 0 or y >= height)
def clear():
global buffer
buffer = [[[0, 0, 0] for _ in range(width)] for y in range(height)]
hat.clear()
def show():
global old_buffer
for y in range(height):
for x in range(width):
px = [(int((buffer[y][x][i] + old_buffer[y][x][i])) / 2)
for i in range(3)]
hat.set_pixel(*map_coords(x, y), *px)
hat.show()
old_buffer = deepcopy(buffer)
def off():
hat.off()
def set_brightness(level):
min_val, max_val = led_options.get(
'minBrightness', 0.01), led_options.get('maxBrightness', 1.0)
brightness = min_val + ((max_val - min_val) * level)
hat.brightness(brightness)
time_behind = 0
time_behind_max = 0.5
def loop_draw(draw_func):
global time_behind
secs_per_frame = 1 / led_options.get('fps', 10)
try:
while True:
loop_start_time = time.time()
clear()
set_brightness(get_brightness_level())
draw_func()
show()
# Calculate how long we have left in the loop to sleep
loop_finish_time = time.time()
loop_duration = loop_finish_time - loop_start_time
sleep_duration = secs_per_frame - loop_duration
# Ensure consistent frame rate
if sleep_duration >= time_behind:
sleep_duration -= time_behind
time_behind = 0
else:
time_behind -= sleep_duration
time_behind = min(time_behind, time_behind_max)
sleep_duration = 0
time.sleep(sleep_duration)
except KeyboardInterrupt:
off()
hat.rotation(led_options.get('rotation', 0))
setup()