Galactic Unicorn: Backport Cosmic ulab/numpy examples.

pull/697/head
Phil Howard 2023-02-27 20:47:39 +00:00
rodzic d750532180
commit c836f9f8fe
6 zmienionych plików z 655 dodań i 0 usunięć

Wyświetl plik

@ -0,0 +1,88 @@
import gc
import time
import random
from galactic import GalacticUnicorn
from picographics import PicoGraphics, DISPLAY_GALACTIC_UNICORN, PEN_P8
from ulab import numpy
"""
A random, computer effect.
Experiment with the damping, number of spawns and intensity to change the effect.
"""
# MAXIMUM OVERKILL
# machine.freq(250_000_000)
gu = GalacticUnicorn()
gu.set_brightness(0.5)
graphics = PicoGraphics(DISPLAY_GALACTIC_UNICORN, pen_type=PEN_P8)
DAMPING_FACTOR = 0.95
NUMBER_OF_LIGHTS = 10
INTENSITY = 20
# Fill palette with a yellow
r, g, b = (230, 150, 0)
PALETTE_ENTRIES = 255
for x in range(PALETTE_ENTRIES):
_ = graphics.create_pen(r * x // PALETTE_ENTRIES, g * x // PALETTE_ENTRIES, b)
def update():
computer[:] *= DAMPING_FACTOR
# Spawn random drops
for _ in range(NUMBER_OF_LIGHTS):
x = random.randint(0, width - 1)
y = random.randint(0, height - 1)
computer[y][x] = random.randint(0, INTENSITY)
def draw():
# Copy the effect to the framebuffer
memoryview(graphics)[:] = numpy.ndarray(numpy.clip(computer, 0, 1) * (PALETTE_ENTRIES - 1), dtype=numpy.uint8).tobytes()
gu.update(graphics)
width = GalacticUnicorn.WIDTH
height = GalacticUnicorn.HEIGHT
computer = numpy.zeros((height, width))
t_count = 0
t_total = 0
while True:
if gu.is_pressed(GalacticUnicorn.SWITCH_BRIGHTNESS_UP):
gu.adjust_brightness(+0.01)
if gu.is_pressed(GalacticUnicorn.SWITCH_BRIGHTNESS_DOWN):
gu.adjust_brightness(-0.01)
tstart = time.ticks_ms()
gc.collect()
update()
draw()
tfinish = time.ticks_ms()
total = tfinish - tstart
t_total += total
t_count += 1
if t_count == 60:
per_frame_avg = t_total / t_count
print(f"60 frames in {t_total}ms, avg {per_frame_avg:.02f}ms per frame, {1000/per_frame_avg:.02f} FPS")
t_count = 0
t_total = 0
# pause for a moment (important or the USB serial device will fail)
# try to pace at 60fps or 30fps
if total > 1000 / 30:
time.sleep(0.0001)
elif total > 1000 / 60:
t = 1000 / 30 - total
time.sleep(t / 1000)
else:
t = 1000 / 60 - total
time.sleep(t / 1000)

Wyświetl plik

@ -0,0 +1,128 @@
import time
import gc
import random
from galactic import GalacticUnicorn
from picographics import PicoGraphics, DISPLAY_GALACTIC_UNICORN, PEN_P8
from ulab import numpy
"""
Classic fire effect.
Play with the number of spawns, heat, damping factor and colour palette to tweak it.
This is vertical because my brain would not let me rotate it.
"""
# MAXIMUM OVERKILL
# machine.freq(250_000_000)
gu = GalacticUnicorn()
gu.set_brightness(0.5)
graphics = PicoGraphics(DISPLAY_GALACTIC_UNICORN, pen_type=PEN_P8)
# Number of random fire spawns
FIRE_SPAWNS = 5
# Fire damping
DAMPING_FACTOR = 0.98
# TURN UP THE HEEEAAT
HEAT = 3.0
# Create the fire palette
"""
# Raging Gas Inferno
graphics.create_pen(0, 0, 0)
graphics.create_pen(0, 0, 0)
graphics.create_pen(20, 20, 20)
graphics.create_pen(50, 10, 0)
graphics.create_pen(180, 30, 0)
graphics.create_pen(220, 160, 0)
graphics.create_pen(255, 255, 180)
graphics.create_pen(255, 255, 220)
graphics.create_pen(90, 90, 255)
graphics.create_pen(255, 0, 255)
"""
# Original Colours
graphics.create_pen(0, 0, 0)
graphics.create_pen(20, 20, 20)
graphics.create_pen(180, 30, 0)
graphics.create_pen(220, 160, 0)
graphics.create_pen(255, 255, 180)
PALETTE_SIZE = 5 # Should match the number of colours defined above
def update():
# Clear the bottom two rows (off screen)
heat[height - 1][:] = 0.0
heat[height - 2][:] = 0.0
# Add random fire spawns
for c in range(FIRE_SPAWNS):
x = random.randint(0, width - 4) + 2
heat[height - 1][x - 1:x + 1] = HEAT / 2.0
heat[height - 2][x - 1:x + 1] = HEAT
# Propagate the fire upwards
a = numpy.roll(heat, -1, axis=0) # y + 1, x
b = numpy.roll(heat, -2, axis=0) # y + 2, x
c = numpy.roll(heat, -1, axis=0) # y + 1
d = numpy.roll(c, 1, axis=1) # y + 1, x + 1
e = numpy.roll(c, -1, axis=1) # y + 1, x - 1
# Average over 5 adjacent pixels and apply damping
heat[:] += a + b + d + e
heat[:] *= DAMPING_FACTOR / 5.0
def draw():
# Copy the fire effect to the framebuffer
# Clips the fire to 0.0 to 1.0
# Multiplies it by the number of palette entries (-1) to turn it into a palette index
# Converts to uint8_t datatype to match the framebuffer
memoryview(graphics)[:] = numpy.ndarray(numpy.clip(heat[0:11, 0:53], 0, 1) * (PALETTE_SIZE - 1), dtype=numpy.uint8).tobytes()
gu.update(graphics)
width = GalacticUnicorn.WIDTH
height = GalacticUnicorn.HEIGHT + 4
heat = numpy.zeros((height, width))
t_count = 0
t_total = 0
while True:
gc.collect()
if gu.is_pressed(GalacticUnicorn.SWITCH_BRIGHTNESS_UP):
gu.adjust_brightness(+0.01)
if gu.is_pressed(GalacticUnicorn.SWITCH_BRIGHTNESS_DOWN):
gu.adjust_brightness(-0.01)
tstart = time.ticks_ms()
gc.collect()
update()
draw()
tfinish = time.ticks_ms()
total = tfinish - tstart
t_total += total
t_count += 1
if t_count == 60:
per_frame_avg = t_total / t_count
print(f"60 frames in {t_total}ms, avg {per_frame_avg:.02f}ms per frame, {1000/per_frame_avg:.02f} FPS")
t_count = 0
t_total = 0
# pause for a moment (important or the USB serial device will fail)
# try to pace at 60fps or 30fps
if total > 1000 / 30:
time.sleep(0.0001)
elif total > 1000 / 60:
t = 1000 / 30 - total
time.sleep(t / 1000)
else:
t = 1000 / 60 - total
time.sleep(t / 1000)

Wyświetl plik

@ -0,0 +1,120 @@
import gc
import time
import math
import random
from galactic import GalacticUnicorn
from picographics import PicoGraphics, DISPLAY_GALACTIC_UNICORN, PEN_P8
from ulab import numpy
"""
A lava lamp effect, created by blurred, moving particles.
Oh boy, this one's real lively! Stand your Galactic Unicorn on its side for best effect.
"""
# MAXIMUM OVERKILL
# machine.freq(250_000_000)
gu = GalacticUnicorn()
graphics = PicoGraphics(DISPLAY_GALACTIC_UNICORN, pen_type=PEN_P8)
gu.set_brightness(0.5)
width = GalacticUnicorn.WIDTH
height = GalacticUnicorn.HEIGHT
lava = numpy.zeros((height, width))
class Blob():
def __init__(self):
self.x = float(random.randint(0, width - 1))
self.y = float(random.randint(0, height - 1))
self.r = (float(random.randint(0, 40)) / 5.0)
self.dx = (float(random.randint(0, 20)) / 80.0)
self.dy = (float(random.randint(0, 20)) / 80.0) - 0.15
def move(self):
self.x += self.dx
self.y += self.dy
if self.x < 0.0 or self.x >= float(width):
self.x = max(0.0, self.x)
self.x = min(float(width - 1), self.x)
self.dx = -self.dx
if self.y < 0.0 or self.y >= float(height):
self.y = max(0.0, self.y)
self.y = min(float(height - 1), self.y)
self.dy = -self.dy
blobs = [Blob() for _ in range(10)]
# Fill palette with a steep falloff from bright red to dark blue
PAL_COLS = 9
for x in range(PAL_COLS):
graphics.create_pen_hsv(0.5 + math.log(x + 1, PAL_COLS + 1) / 2.0, 1.0, math.log(x + 1, PAL_COLS + 1))
def update():
# Update the blobs and draw them into the effect
for blob in blobs:
blob.move()
lava[int(blob.y)][int(blob.x)] = blob.r
# Propogate the blobs outwards
a = numpy.roll(lava, 1, axis=0)
b = numpy.roll(lava, -1, axis=0)
d = numpy.roll(lava, 1, axis=1)
e = numpy.roll(lava, -1, axis=1)
# Average over 5 adjacent pixels and apply damping
lava[:] += a + b + d + e
lava[:] *= 0.97 / 5.0
def draw():
# Copy the lava effect to the framebuffer
# Clips to 0.0 - 1.0
# Multiplies by palette entries (-1) to turn it into a palette index
# Converts to uint8_t datatype to match the framebuffer
memoryview(graphics)[:] = numpy.ndarray(numpy.clip(lava, 0.0, 1.0) * (PAL_COLS - 1), dtype=numpy.uint8).tobytes()
gu.update(graphics)
t_count = 0
t_total = 0
while True:
if gu.is_pressed(GalacticUnicorn.SWITCH_BRIGHTNESS_UP):
gu.adjust_brightness(+0.01)
if gu.is_pressed(GalacticUnicorn.SWITCH_BRIGHTNESS_DOWN):
gu.adjust_brightness(-0.01)
tstart = time.ticks_ms()
gc.collect()
update()
draw()
tfinish = time.ticks_ms()
total = tfinish - tstart
t_total += total
t_count += 1
if t_count == 60:
per_frame_avg = t_total / t_count
print(f"60 frames in {t_total}ms, avg {per_frame_avg:.02f}ms per frame, {1000/per_frame_avg:.02f} FPS")
t_count = 0
t_total = 0
# pause for a moment (important or the USB serial device will fail)
# try to pace at 60fps or 30fps
if total > 1000 / 30:
time.sleep(0.0001)
elif total > 1000 / 60:
t = 1000 / 30 - total
time.sleep(t / 1000)
else:
t = 1000 / 60 - total
time.sleep(t / 1000)

Wyświetl plik

@ -0,0 +1,88 @@
import gc
import time
import random
from galactic import GalacticUnicorn
from picographics import PicoGraphics, DISPLAY_GALACTIC_UNICORN, PEN_P8
from ulab import numpy
"""
HELLO NEO.
"""
# MAXIMUM OVERKILL
# machine.freq(250_000_000)
gu = GalacticUnicorn()
gu.set_brightness(1.0)
graphics = PicoGraphics(DISPLAY_GALACTIC_UNICORN, pen_type=PEN_P8)
# Fill half the palette with GREEEN
for g in range(128):
_ = graphics.create_pen(0, g, 0)
# And half with bright green for white sparkles
for g in range(128):
_ = graphics.create_pen(128, 128 + g, 128)
def update():
the_matrix[:] *= 0.65
x = random.randint(0, width // 2)
y = random.randint(0, height - 1)
the_matrix[y][x] = random.randint(128, 255) / 255.0
# Propagate downwards
old = numpy.ndarray(the_matrix) * 0.5
the_matrix[:] = numpy.roll(the_matrix, 1, axis=1)
the_matrix[:] += old
def draw():
# Copy the effect to the framebuffer
memoryview(graphics)[:] = numpy.ndarray(numpy.clip(the_matrix, 0, 1) * 254, dtype=numpy.uint8).tobytes()
gu.update(graphics)
width = GalacticUnicorn.WIDTH
height = GalacticUnicorn.HEIGHT
the_matrix = numpy.zeros((height, width))
t_count = 0
t_total = 0
while True:
if gu.is_pressed(GalacticUnicorn.SWITCH_BRIGHTNESS_UP):
gu.adjust_brightness(+0.01)
if gu.is_pressed(GalacticUnicorn.SWITCH_BRIGHTNESS_DOWN):
gu.adjust_brightness(-0.01)
tstart = time.ticks_ms()
gc.collect()
update()
draw()
tfinish = time.ticks_ms()
total = tfinish - tstart
t_total += total
t_count += 1
if t_count == 60:
per_frame_avg = t_total / t_count
print(f"60 frames in {t_total}ms, avg {per_frame_avg:.02f}ms per frame, {1000/per_frame_avg:.02f} FPS")
t_count = 0
t_total = 0
# pause for a moment (important or the USB serial device will fail)
# try to pace at 60fps or 30fps
if total > 1000 / 30:
time.sleep(0.0001)
elif total > 1000 / 60:
t = 1000 / 30 - total
time.sleep(t / 1000)
else:
t = 1000 / 60 - total
time.sleep(t / 1000)

Wyświetl plik

@ -0,0 +1,134 @@
import time
import gc
import random
from galactic import GalacticUnicorn
from picographics import PicoGraphics, DISPLAY_GALACTIC_UNICORN, PEN_P8
from ulab import numpy
"""
Classic fire effect.
Play with the number of spawns, heat, damping factor and colour palette to tweak it.
This is vertical because my brain would not let me rotate it.
"""
# MAXIMUM OVERKILL
# machine.freq(250_000_000)
gu = GalacticUnicorn()
gu.set_brightness(0.5)
graphics = PicoGraphics(DISPLAY_GALACTIC_UNICORN, pen_type=PEN_P8)
# Number of random fire spawns
FIRE_SPAWNS = 5
# Fire damping
DAMPING_FACTOR = 0.98
# TURN UP THE HEEEAAT
HEAT = 3.0
# Create the fire palette
"""
# Raging Gas Inferno
graphics.create_pen(0, 0, 0)
graphics.create_pen(0, 0, 0)
graphics.create_pen(20, 20, 20)
graphics.create_pen(50, 10, 0)
graphics.create_pen(180, 30, 0)
graphics.create_pen(220, 160, 0)
graphics.create_pen(255, 255, 180)
graphics.create_pen(255, 255, 220)
graphics.create_pen(90, 90, 255)
graphics.create_pen(255, 0, 255)
"""
# Original Colours
graphics.create_pen(0, 0, 0)
graphics.create_pen(20, 20, 20)
graphics.create_pen(180, 30, 0)
graphics.create_pen(220, 160, 0)
graphics.create_pen(255, 255, 180)
PALETTE_SIZE = 5 # Should match the number of colours defined above
def update():
# Clear the bottom two rows (off screen)
heat[height - 1][:] = 0.0
heat[height - 2][:] = 0.0
# Add random fire spawns
for c in range(FIRE_SPAWNS):
x = random.randint(0, width - 4) + 2
heat[height - 1][x - 1:x + 1] = HEAT / 2.0
heat[height - 2][x - 1:x + 1] = HEAT
# Propagate the fire upwards
a = numpy.roll(heat, -1, axis=0) # y + 1, x
b = numpy.roll(heat, -2, axis=0) # y + 2, x
c = numpy.roll(heat, -1, axis=0) # y + 1
d = numpy.roll(c, 1, axis=1) # y + 1, x + 1
e = numpy.roll(c, -1, axis=1) # y + 1, x - 1
# Average over 5 adjacent pixels and apply damping
heat[:] += a + b + d + e
heat[:] *= DAMPING_FACTOR / 5.0
def draw():
# Copy the fire effect to the framebuffer
# Clips the fire to 0.0 to 1.0
# Multiplies it by the number of palette entries (-1) to turn it into a palette index
# Converts to uint8_t datatype to match the framebuffer
memoryview(graphics)[:] = numpy.ndarray(numpy.clip(heat[0:11, 0:53], 0, 1) * (PALETTE_SIZE - 1), dtype=numpy.uint8).tobytes()
# Draw text over the top
graphics.set_pen(0)
graphics.text("This", 1, 2, 1, 1)
graphics.text("is", 22, 2, 1, 1)
graphics.text("fine", 33, 2, 1, 1)
gu.update(graphics)
width = GalacticUnicorn.WIDTH
height = GalacticUnicorn.HEIGHT + 4
heat = numpy.zeros((height, width))
t_count = 0
t_total = 0
while True:
gc.collect()
if gu.is_pressed(GalacticUnicorn.SWITCH_BRIGHTNESS_UP):
gu.adjust_brightness(+0.01)
if gu.is_pressed(GalacticUnicorn.SWITCH_BRIGHTNESS_DOWN):
gu.adjust_brightness(-0.01)
tstart = time.ticks_ms()
gc.collect()
update()
draw()
tfinish = time.ticks_ms()
total = tfinish - tstart
t_total += total
t_count += 1
if t_count == 60:
per_frame_avg = t_total / t_count
print(f"60 frames in {t_total}ms, avg {per_frame_avg:.02f}ms per frame, {1000/per_frame_avg:.02f} FPS")
t_count = 0
t_total = 0
# pause for a moment (important or the USB serial device will fail)
# try to pace at 60fps or 30fps
if total > 1000 / 30:
time.sleep(0.0001)
elif total > 1000 / 60:
t = 1000 / 30 - total
time.sleep(t / 1000)
else:
t = 1000 / 60 - total
time.sleep(t / 1000)

Wyświetl plik

@ -0,0 +1,97 @@
import gc
import time
import random
from galactic import GalacticUnicorn
from picographics import PicoGraphics, DISPLAY_GALACTIC_UNICORN, PEN_P8
from ulab import numpy
"""
A random, trippy effect.
Experiment with the damping, number of spawns, intensity and offset to change the effect.
"""
# MAXIMUM OVERKILL
# machine.freq(250_000_000)
gu = GalacticUnicorn()
gu.set_brightness(0.5)
graphics = PicoGraphics(DISPLAY_GALACTIC_UNICORN, pen_type=PEN_P8)
DAMPING_FACTOR = 0.95
NUMBER_OF_DROPS = 5
INTENSITY = 10
OFFSET = 0.0 # Try 0.5
# Fill palette with a rainbow sweep
PALETTE_ENTRIES = 255
for x in range(PALETTE_ENTRIES):
_ = graphics.create_pen_hsv(float(x) / PALETTE_ENTRIES + OFFSET, 1.0, 1.0)
def update():
trippy[:] *= DAMPING_FACTOR
# Spawn random drops
for _ in range(NUMBER_OF_DROPS):
x = random.randint(0, width - 1)
y = random.randint(0, height - 1)
trippy[y][x] = random.randint(0, INTENSITY)
a = numpy.roll(trippy, 1, axis=0)
b = numpy.roll(trippy, -1, axis=0)
d = numpy.roll(trippy, 1, axis=1)
e = numpy.roll(trippy, -1, axis=1)
# Average over 5 adjacent pixels and apply damping
trippy[:] += a + b + d + e
trippy[:] /= 5.0
def draw():
# Copy the effect to the framebuffer
memoryview(graphics)[:] = numpy.ndarray(numpy.clip(trippy, 0, 1) * (PALETTE_ENTRIES - 1), dtype=numpy.uint8).tobytes()
gu.update(graphics)
width = GalacticUnicorn.WIDTH
height = GalacticUnicorn.HEIGHT
trippy = numpy.zeros((height, width))
t_count = 0
t_total = 0
while True:
if gu.is_pressed(GalacticUnicorn.SWITCH_BRIGHTNESS_UP):
gu.adjust_brightness(+0.01)
if gu.is_pressed(GalacticUnicorn.SWITCH_BRIGHTNESS_DOWN):
gu.adjust_brightness(-0.01)
tstart = time.ticks_ms()
gc.collect()
update()
draw()
tfinish = time.ticks_ms()
total = tfinish - tstart
t_total += total
t_count += 1
if t_count == 60:
per_frame_avg = t_total / t_count
print(f"60 frames in {t_total}ms, avg {per_frame_avg:.02f}ms per frame, {1000/per_frame_avg:.02f} FPS")
t_count = 0
t_total = 0
# pause for a moment (important or the USB serial device will fail)
# try to pace at 60fps or 30fps
if total > 1000 / 30:
time.sleep(0.0001)
elif total > 1000 / 60:
t = 1000 / 30 - total
time.sleep(t / 1000)
else:
t = 1000 / 60 - total
time.sleep(t / 1000)