From b8f9495e0cf2f500edb620f828aba2afab8f8f68 Mon Sep 17 00:00:00 2001 From: Aaron Perley Date: Sun, 16 Oct 2016 23:47:08 -0400 Subject: Basic twinkle --- ShowRunner.py | 6 +- twinkle.py | 242 ++++++++++++++++++++++++++++++++-------------------------- 2 files changed, 139 insertions(+), 109 deletions(-) diff --git a/ShowRunner.py b/ShowRunner.py index 05877ed..618e80c 100644 --- a/ShowRunner.py +++ b/ShowRunner.py @@ -1,6 +1,7 @@ from bridge import Bridge from fish_show import FishShow from sunrise import SunriseShow +from twinkle import TwinkleShow from constants import * import sys @@ -10,8 +11,9 @@ from run import server_thread, send_queue, recv_queue def run_show(): server_thread.start() bridge = Bridge() - SunriseShow(bridge, send_queue=recv_queue, recv_queue=send_queue).run(framerate=FRAME_RATE) - FishShow(bridge, send_queue=recv_queue, recv_queue=send_queue).run(framerate=FRAME_RATE) + #SunriseShow(bridge, send_queue=recv_queue, recv_queue=send_queue).run(framerate=FRAME_RATE) + #FishShow(bridge, send_queue=recv_queue, recv_queue=send_queue).run(framerate=FRAME_RATE) + TwinkleShow(bridge, send_queue=recv_queue, recv_queue=send_queue).run(framerate=FRAME_RATE) print "done!" run_show() \ No newline at end of file diff --git a/twinkle.py b/twinkle.py index a2cb3d2..5a452a2 100755 --- a/twinkle.py +++ b/twinkle.py @@ -1,112 +1,140 @@ -#!/usr/bin/python2 -"""Simple demo of twinkle lights.""" +"""Rendering classes and helper functions.""" from __future__ import division import color +import random import constants -#from DummyRig import DummyRig -from fish_render import * -import fish_render from constants import * -import time -import random -try: - import lumiversepython -except ImportError: - have_lumiversepython = False -else: - have_lumiversepython = True - -def get_all_lights(rig): - """Return a list of all panels.""" - return [ - [ - fish_render.Light( - x, int(y == 'top'), - rig.select('$side={y}[$sequence={x}]'.format(y=y, x=x)) - ) for y in ('top', 'bot') - ] for x in xrange(1, 200) - ] - -def flip(): - """Return 0 with 99.9% prob. & 1 with .1% prob.""" - # should be black most of the time - return random.random() < 0.0005 - - -def twinkle(lights, rig): - """Try to do some light things.""" - light_status = [ - { - 'is_increasing': True, - 'is_on': False, - 'change': random_change(), - 'light': light, - 'intensity': 0, - } - for light_col in lights for light in light_col - ] - shooting_stars = list() - while True: - if random.random() < 1: - shooting_stars.append([random.randint(1, 180), random.random() < 0.5, 0]) - for light_s in light_status: - is_increasing = light_s['is_increasing'] - is_on = light_s['is_on'] - change = light_s['change'] - light = light_s['light'] - intensity = light_s['intensity'] - # R and G are either 0 or 1 - if not is_on: - if flip(): - is_on = True - is_increasing = True - change = 1.5 / FRAME_RATE - light_s['is_on'] = is_on - light_s['is_increasing'] = is_increasing - light_s['change'] = change +import math +from show import Show + +class ShootingStar(object): + """Object displayed on the bridge, probably a fish.""" + def __init__(self): + """Create fish with default parameters.""" + self.x = 0 + self.y = random.random() * 1.5 + self.width = 5 + self.height = 0.5 + self.color = color.RGB(255/255, 210/255, 201/255) + + def update(self): + self.x += 0.1 + + +class Light(object): + """Represent a bridge light and its state.""" + def __init__(self, x, y, light): + """Store all facts about a light.""" + self.light = light + self.color = color.black + self.transitioning_to = self.color + self.step = 0 + self.on = False + self.increasing = False + self.x = x + self.y = y + self.fade_step = 0 + + def update(self): + """Change color depending on where the fish is.""" + if not self.on and random.random() < 0.0005: + self.transitioning_to = color.RGB(1, 1, 1) + self.step = abs(self.transitioning_to - self.color) / (FRAME_RATE / 2) + self.increasing = True + self.on = True + self.color = transition(self.color, self.transitioning_to, self.step) + elif self.on: + if abs(self.transitioning_to - self.color) <= self.step: + if self.increasing == True: + self.transitioning_to = color.RGB(0, 0, 0) + self.step = abs(self.transitioning_to - self.color) / (FRAME_RATE / 2) + self.increasing = False else: - continue - intensity = clamp(0, intensity + change * (int(is_increasing) * 2 - 1), 1) - light.light.setRGBRaw(intensity, intensity, intensity) - light_s['intensity'] = intensity - if intensity == 0: - light_s['is_on'] = False - if intensity == 1: - light_s['is_increasing'] = False - for i, star in enumerate(shooting_stars): - star[2] += 1 - if star[2] > 10: - for dx in range(-6, 7): - light_status[star[0] + dx]['light'].light.setRGBRaw(0, 0, 0) - del shooting_stars[i] - continue - star[0] += int(star[1]) * 2 - 1 - for dx in range(-6, 7): - intensity = 1 - 1 / 6 * abs(dx) - light_status[star[0] + dx]['light'].light.setRGBRaw(intensity, intensity, intensity) - rig.updateOnce() - time.sleep(1 / FRAME_RATE) - -def sunrise(lights, rig): - #rig.select('$side={y}[$sequence={x}]'.format(y=y, x=x)) - rig.select("$side=top[$panel=27|$panel=28]") - rig.updateOnce() - time.sleep(1) - - -def main(): - """Run show.""" - if have_lumiversepython: - rig = lumiversepython.Rig('/home/teacher/Lumiverse/PBridge.rig.json') - else: - rig = DummyRig(200, 2) - rig.init() - lights = get_all_lights(rig) - #for light in lights: - # light.setRGBRaw(0, 0, 0) - rig.updateOnce() - time.sleep(3) - twinkle(lights, rig) - -if __name__ == '__main__': - main() + self.increasing = False + self.on = False + self.color = transition(self.color, self.transitioning_to, self.step) + + self.light.setRGBRaw( + *map(lambda x: clamp(0, x, 1), self.color.components) + ) + + + def fade_to_black(self, steps): + hue = self.color.to_HSV().h() + sat = self.color.to_HSV().s() + value = self.color.to_HSV().v() + new_color = color.HSV(hue, sat, value - value / steps * self.fade_step).to_RGB() + self.fade_step += 1 + self.light.setRGBRaw(*map(lambda x: clamp(0, x, 1), new_color.components)) + + +class TwinkleShow(Show): + def init(self): + self.lights = [Light(x, y, self.bridge.get_light(x, y)) + for y in xrange(self.bridge.HEIGHT) + for x in xrange(self.bridge.WIDTH)] + #self.sun = Sun() + self.tick_count = 0 + + + def update(self): + if self.tick_count > 1000: + fade_time = 3 # sec + if self.tick_count > 1000 + fade_time * FRAME_RATE: + self.stop() + return + for light in self.lights: + light.fade_to_black(fade_time * FRAME_RATE) + else: + for light in self.lights: + light.update() + + self.tick_count += 1 + print self.tick_count + + +def compute_coverage(fish, x, y): + """Calculate the coverage of a fish over a box.""" + middle_of_fish = fish.x + fish.width / 2 + middle_of_panel = x + 0.5 + diff = abs(middle_of_fish - middle_of_panel) / (fish.width / 2) + scale = 1 - diff + min_x = min(max(x, fish.x), x + 1) + max_x = max(min(x+1, fish.x + fish.width), x) + min_y = min(max(y, fish.y), y + 1) + max_y = max(min(y+1, fish.y + fish.height), y) + coverage = (max_x - min_x) * (max_y - min_y) + return coverage * scale + + +def pick_ocean_HSV(sky_brightness): + """Return a random color in an appropriate interval.""" + min_hue = 236 / 360 + max_hue = 250 / 360 + min_sat = 0.25 + max_sat = 0.6 + hue = random.random() * (max_hue - min_hue) + min_hue + saturation = random.random() * (max_sat - min_sat) + min_sat + return color.HSV(hue, saturation, sky_brightness) + + +def transition(start, end, step): + """Return a vector equal to (end - start) * step + start.""" + if start == end: + return start + diff_vector = end - start + step_vector = diff_vector / abs(diff_vector) * step + result = step_vector + start + return result + + +def random_change(): + """Return a random amount that a light should change each frame.""" + min_time = int(2 * FRAME_RATE) + max_time = int(6 * FRAME_RATE) + return 1 / random.randint(min_time, max_time) + + +def clamp(low, x, high): + """Return v such that low <= v <= high and |x - v| is minimal.""" + return max(low, min(x, high)) -- cgit v1.3.1