Last active
May 20, 2024 01:16
-
-
Save todbot/194298619de3cadb0c9f531b2461286a to your computer and use it in GitHub Desktop.
qteye.py but on a PicoDVI RP2040 board in CircuitPython
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# qteye_picodvi.py - qteye.py but on a PicoDVI RP2040 board | |
# 19 May 2024 - @todbot, on a DJDevon3 suggestion in Discord | |
# 23 Oct 2022 - @todbot / Tod Kurt | |
# Part of https://github.com/todbot/CircuitPython_GC9A01_demos | |
# also see: https://twitter.com/todbot/status/1584309133263532033 | |
# and: https://twitter.com/todbot/status/1584309133263532033 | |
# Copy this file as "code.py" and the two eyeball BMP files to CIRCUITPY drive | |
# To install needed libraries: "circup install adafruit_imageload" | |
# | |
# Video demo below as a comment to this gist | |
import time, math, random | |
import board, busio | |
import displayio | |
import adafruit_imageload | |
display = board.DISPLAY | |
dw, dh = display.width, display.height # display dimensions | |
# load our eye and iris bitmaps | |
#eyeball_bitmap, eyeball_pal = adafruit_imageload.load("imgs/eye0_ball2.bmp") | |
# can't load both bitmaps fully in RAM on PicoDVI, so background eyeball is OnDisk | |
eyeball_bitmap = displayio.OnDiskBitmap("imgs/eye0_ball2.bmp") | |
eyeball_pal = eyeball_bitmap.pixel_shader | |
# and moving iris is loaded in RAM | |
iris_bitmap, iris_pal = adafruit_imageload.load("imgs/eye0_iris0.bmp") | |
iris_pal.make_transparent(0) # palette color #0 is our transparent background | |
# compute or declare some useful info about the eyes | |
iris_w, iris_h = iris_bitmap.width, iris_bitmap.height # iris is normally 110x110 | |
iris_cx, iris_cy = dw//2 - iris_w//2, dh//2 - iris_h//2 | |
r = 20 # allowable deviation from center for iris | |
main = displayio.Group() | |
display.root_group = main | |
# class to help us track eye info (not needed for this use exactly, but I find it interesting) | |
class Eye: | |
def __init__(self, display, main_group, rot=0, eye_speed=0.25, twitch=2): | |
self.display = display | |
self.main_group = main_group | |
self.eyeball = displayio.TileGrid(eyeball_bitmap, pixel_shader=eyeball_pal) | |
self.eyeball.x = (dw - eyeball_bitmap.width) // 2 | |
self.iris = displayio.TileGrid(iris_bitmap, pixel_shader=iris_pal, x=iris_cx,y=iris_cy) | |
self.main_group.append(self.eyeball) | |
self.main_group.append(self.iris) | |
self.x, self.y = iris_cx, iris_cy | |
self.tx, self.ty = self.x, self.y | |
self.next_time = time.monotonic() | |
self.eye_speed = eye_speed | |
self.twitch = twitch | |
def update(self): | |
self.x = self.x * (1-self.eye_speed) + self.tx * self.eye_speed # "easing" | |
self.y = self.y * (1-self.eye_speed) + self.ty * self.eye_speed | |
self.iris.x = int( self.x ) | |
self.iris.y = int( self.y ) | |
if time.monotonic() > self.next_time: | |
t = random.uniform(0.25,self.twitch) | |
self.next_time = time.monotonic() + t | |
self.tx = iris_cx + random.uniform(-r,r) | |
self.ty = iris_cy + random.uniform(-r,r) | |
self.display.refresh() | |
# a list of all the eyes, in this case, only one | |
the_eyes = [ | |
Eye( display, main, rot=0), | |
] | |
while True: | |
for eye in the_eyes: | |
eye.update() | |
That's one giant eyeball. Very nice!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Video demo:
IMG_3834.mov