pybeamshow/effects/presets.py
2023-03-05 02:37:18 +01:00

597 lines
19 KiB
Python

import pygame as pg
from typing import Iterator, List
from random import choice, randint, randrange
from effects.chase_circle import ChaseCircle
from effects.effect import Effect
from effects.line import Lines
from effects.rectangle import Rectangle
from util.color import (
color_darken,
color_randomize,
color_static,
color_strobe,
color_wheel,
Colors,
)
# from effects.crazypolys import CrazyPolys
from effects.drops import Drops
from effects.bouncingspot import BouncingSpot
from effects.doublespot import DoubleSpot
from effects.moonflower import Moonflower
from effects.rainbowwave import RainbowWave
from effects.rotatingpoly import RotatingPoly
from effects.scanreticle import ScanReticle
# from effects.spiro import Spiro
from effects.starfield import Starfield
from util.transform import (
transform_bounce,
transform_falling,
transform_oscillate,
transform_static,
)
class Presets:
def __init__(self, bounds: pg.Rect, beat_reactive: bool = False) -> None:
self.bounds = bounds
self.beat_reactive = beat_reactive
self.shuffles = list(iter(self)) * 2
def default(self) -> List[Effect]:
return self.DoubleBouncingSpotsColorWheel()
def __getitem__(self, idx: str) -> List[Effect]:
return getattr(self, idx)()
def __contains__(self, idx: str) -> bool:
return hasattr(self, idx)
def __iter__(self) -> Iterator[str]:
return (
func
for func in dir(self)
if callable(getattr(self, func))
and not (func.startswith("__") or func == "randomize")
)
def randomize(self) -> str:
selected = choice(self.shuffles)
self.shuffles.remove(selected)
if not self.shuffles:
self.shuffles = list(iter(self)) * 2
return selected
# return choice(
# [
# func
# for func in dir(self)
# if callable(getattr(self, func))
# and not (func.startswith("__") or func == "randomize")
# ]
# )
def DoubleSpotRandomColor(self) -> List[Effect]:
return [
DoubleSpot(
bounds=self.bounds,
color=color_wheel(increase=30),
beat_adapt=self.beat_reactive,
radius=100,
fade_out=True,
fade_in=True,
hold=60,
)
]
def DoubleBouncingSpotsColorWheel(self) -> List[Effect]:
return [
BouncingSpot(
bounds=self.bounds,
color=color_wheel(),
sizes=(self.bounds.height / 8, self.bounds.height / 6),
mover=transform_bounce(
bounds=self.bounds,
velocity=(1, 1),
x_factor=(1, 1),
y_factor=(2.2, 2.2),
on_beat_phase=90,
),
),
BouncingSpot(
bounds=self.bounds,
color=color_wheel(hue=180),
sizes=(self.bounds.height / 8, self.bounds.height / 6),
mover=transform_bounce(
bounds=self.bounds,
velocity=(1, 1),
x_factor=(1, 1),
y_factor=(2.2, 2.2),
on_beat_phase=180,
),
),
]
def CollidingWaves(self) -> List[Effect]:
return [
RainbowWave(
bounds=pg.rect.Rect(0, 0, self.bounds.width, self.bounds.height),
wave_count=5,
wave_height=self.bounds.height // 6,
thickness=30,
mover=transform_oscillate(self.bounds, 60, (0, 0)),
),
RainbowWave(
bounds=pg.rect.Rect(0, 0, self.bounds.width, self.bounds.height),
# hue=180,
wave_count=5,
wave_height=self.bounds.height // 6,
start_phase=120,
thickness=20,
mover=transform_oscillate(
self.bounds, 60, (0, self.bounds.height * 5 // 6)
),
),
]
def RainbowWave(self) -> List[Effect]:
return [
RainbowWave(
bounds=pg.rect.Rect(0, 0, self.bounds.width, self.bounds.height),
wave_count=1,
color_inc=2,
wave_height=self.bounds.height // 3,
thickness=30,
mover=transform_static(position=(0, 0)),
),
]
def FallingWave(self) -> List[Effect]:
bounds = pg.rect.Rect(0, 0, self.bounds.width, self.bounds.height // 2)
return [
RainbowWave(
bounds=bounds,
wave_count=8,
wave_height=self.bounds.height // 8,
thickness=25,
hue=30 * randrange(0, 12),
color_inc=0,
scroll_speed=0,
mover=transform_falling(
bounds,
acceleration=0.8,
initial_pos=(0, 0),
initial_velocity=0.01,
on_beat_reset=True,
),
),
]
def BouncingSpotWhite(self) -> List[Effect]:
return [
BouncingSpot(
bounds=self.bounds,
color=color_static(Colors.White),
sizes=(self.bounds.height / 3, self.bounds.height / 3),
velocity=(1, 1),
mover=transform_bounce(
bounds=self.bounds,
velocity=(1, 1),
x_factor=(1, 1),
y_factor=(2.2, 2.2),
on_beat_phase=180,
),
),
]
def RotatingPoly(self) -> List[Effect]:
return [
RotatingPoly(
bounds=self.bounds,
color=color_wheel(increase=(75 if self.beat_reactive else 0)),
beat_color=self.beat_reactive,
size=int(self.bounds.height * 0.8),
outer=randint(3, 8),
rot_speed=1,
mover=transform_bounce(
bounds=self.bounds,
velocity=(0.5, 0.5),
x_factor=(0.5, 1.5),
y_factor=(0.5, 3),
),
)
]
def Moonflower(self) -> List[Effect]:
return [
Moonflower(
bounds=self.bounds,
colors=(
color_wheel(increase=(75 if self.beat_reactive else 0)),
color_wheel(hue=180, increase=(75 if self.beat_reactive else 0)),
),
beat_color=self.beat_reactive,
size=self.bounds.height // 2,
outer=5,
inner_factor=0.3,
rot_speed=1.5,
mover=transform_bounce(
bounds=self.bounds,
velocity=(0.5, 1.5),
x_factor=(0.5, 1.5),
y_factor=(0.5, 1.5),
),
)
]
def DoubleMoonflower(self) -> List[Effect]:
hue_left = randrange(0, 360)
hue_right = randrange(0, 360)
size = int(self.bounds.height * 0.75)
return [
Moonflower(
bounds=self.bounds,
colors=(
color_wheel(
hue=hue_left, increase=(75 if self.beat_reactive else 0)
),
color_wheel(
hue=180 + hue_left, increase=(75 if self.beat_reactive else 0)
),
),
beat_color=self.beat_reactive,
size=size,
outer=7,
inner_factor=0.5,
rot_speed=-1.5,
mover=transform_static(position=(size // 2, self.bounds.height // 2)),
),
Moonflower(
bounds=self.bounds,
colors=(
color_wheel(
hue=hue_right, increase=(75 if self.beat_reactive else 0)
),
color_wheel(
hue=180 + hue_right, increase=(75 if self.beat_reactive else 0)
),
),
beat_color=self.beat_reactive,
size=size,
outer=7,
inner_factor=0.5,
rot_speed=1.7,
mover=transform_static(
position=(self.bounds.width - size // 2, self.bounds.height // 2)
),
),
]
def NestedMoonflower(self) -> List[Effect]:
hue_left = randrange(0, 12) * 30
hue_right = (hue_left + 180) % 360
# hue_right = randrange(0, 360)
size = int(self.bounds.height * 0.8)
return [
Moonflower(
bounds=self.bounds,
colors=(
color_wheel(
hue=hue_left, increase=(15 if self.beat_reactive else 0)
),
color_wheel(
hue=180 + hue_left, increase=(15 if self.beat_reactive else 0)
),
),
beat_color=self.beat_reactive,
size=size,
outer=7,
inner_factor=0.5,
rot_speed=-1.5,
mover=transform_static(
position=(self.bounds.width // 2, self.bounds.height // 2)
),
),
Moonflower(
bounds=self.bounds,
colors=(
color_wheel(
hue=hue_right, increase=(15 if self.beat_reactive else 0)
),
color_wheel(
hue=180 + hue_right, increase=(15 if self.beat_reactive else 0)
),
),
beat_color=self.beat_reactive,
size=int(size * 0.6),
outer=7,
inner_factor=0.3,
rot_speed=1,
mover=transform_static(
position=(self.bounds.width // 2, self.bounds.height // 2)
),
),
]
def WhiteStarfield(self) -> List[Effect]:
return [
Starfield(
bounds=self.bounds,
color=color_static(Colors.White),
# color=color_randomize(),
fade_in=True,
fade_out=True,
# radius=30,
star_factor=1,
hold=60 * 2,
# beat_adapt=True,
)
]
def ColorStarfield(self) -> List[Effect]:
return [
Starfield(
bounds=self.bounds,
color=color_randomize(),
fade_in=True,
fade_out=True,
# radius=30,
star_factor=1,
hold=60 * 2,
beat_adapt=True,
)
]
def GreenBlueDrops(self) -> List[Effect]:
return [
Drops(
bounds=self.bounds,
colors=(
color_static(Colors.Green),
color_static(color_darken(Colors.Blue, 0.2)),
),
sizes=(self.bounds.width // 40, self.bounds.width // 35),
drop_rate=0.1,
drop_acceleration=0.3,
)
]
def ScanReticle(self) -> List[Effect]:
return [
ScanReticle(
self.bounds,
(color_static(Colors.Red), color_static(Colors.White)),
mover=transform_bounce(
bounds=self.bounds,
velocity=(0.5, 1),
x_factor=(2, 2),
y_factor=(0.5, 1),
),
)
]
# def FallingLine(self) -> List[Effect]:
# bounds = pg.rect.Rect(0, 0, self.bounds.width, 30)
# return [
# Lines(
# bounds=bounds,
# vectors=(((0, 15), (self.bounds.width, 15), color_wheel()),),
# thickness=30,
# mover=transform_falling(
# bounds,
# acceleration=0.8,
# initial_pos=(0, 0),
# initial_velocity=0.01,
# on_beat_reset=True,
# ),
# ),
# ]
def StrobeLine(self) -> List[Effect]:
thickness = 50
bounds = pg.rect.Rect(0, 0, self.bounds.width, thickness)
return [
Lines(
bounds=bounds,
vectors=(
(
(0, thickness // 2),
(self.bounds.width, thickness // 2),
color_strobe(color=color_wheel(), rate=(4, 60)),
),
),
thickness=thickness,
mover=transform_static((0, 0)),
),
Lines(
bounds=bounds,
vectors=(
(
(0, thickness // 2),
(self.bounds.width, thickness // 2),
color_strobe(color=color_wheel(), rate=(4, 10)),
),
),
thickness=thickness,
mover=transform_static((0, self.bounds.height - thickness)),
),
]
# def Spiro(self) -> List[Effect]:
# return [
# Spiro(
# bounds=self.bounds,
# color=color_wheel(increase=2),
# sizes=(self.bounds.height, self.bounds.height),
# velocity=(0.1, 0.4),
# mover=transform_bounce(
# self.bounds,
# velocity=(0.1, 0.4),
# x_factor=(1, 1),
# y_factor=(0.5, 1.5),
# ),
# ),
# ]
# def CrazyPolys(self) -> List[Effect]:
# return [
# CrazyPolys(
# bounds=self.bounds,
# color=color_wheel(increase=2),
# sizes=(self.bounds.height, self.bounds.height),
# velocity=(0.1, 0.4),
# y_factor=(0.5, 1.5),
# ),
# ]
def SpotRow(self) -> List[Effect]:
count = 8
size = self.bounds.width // (count * 2)
return [
BouncingSpot(
bounds=self.bounds,
color=color_wheel(hue=3 * 360 // count * i, increase=60),
sizes=(size, size),
velocity=(1, 1),
on_beat_color=True,
mover=transform_static(
(
size + size * 2 * i,
size,
)
),
)
for i in range(count)
]
def OscillateSpotRow(self) -> List[Effect]:
count = 4
size = self.bounds.width // (count * 2)
return [
BouncingSpot(
bounds=self.bounds,
color=color_wheel(hue=180 * i, increase=120),
sizes=(size * 1.5, size * 1.5),
velocity=(1, 1),
on_beat_color=True,
mover=transform_oscillate(
bounds=pg.Rect(
size + size * 2 * i,
size * 1.5 // 2,
size * 1.5,
self.bounds.height,
),
period=120,
auto_period=4,
),
)
for i in range(count)
]
def StrobeRect(self) -> List[Effect]:
thickness = 50
color_lr = color_wheel(hue=0, increase=1, repeat=4)
color_ud = color_wheel(hue=180, increase=1, repeat=4)
color_lr_s = color_strobe(color=color_lr, rate=(30, 120), flash_color=color_ud)
color_ud_s = color_strobe(color=color_ud, rate=(30, 120), flash_color=color_lr)
return [
Lines(
bounds=self.bounds,
vectors=(
(
(0, thickness // 2),
(self.bounds.width, thickness // 2),
color_ud_s,
),
(
(0, self.bounds.height - thickness // 2),
(self.bounds.width, self.bounds.height - thickness // 2),
color_ud_s,
),
),
thickness=thickness,
mover=transform_static((0, 0)),
),
Lines(
bounds=self.bounds,
vectors=(
(
(thickness // 2, 0),
(thickness // 2, self.bounds.height),
color_lr_s,
),
(
(self.bounds.width - thickness // 2, 0),
(self.bounds.width - thickness // 2, self.bounds.height),
color_lr_s,
),
),
thickness=thickness,
mover=transform_static((0, 0)),
),
]
def ChaseCircle(self) -> List[Effect]:
return [
ChaseCircle(
bounds=self.bounds,
colors=(
color_wheel(increase=(75 if self.beat_reactive else 0)),
color_wheel(hue=180, increase=(75 if self.beat_reactive else 0)),
),
on_beat_color=self.beat_reactive,
size=int(self.bounds.height * 0.7),
rot_speed=5,
thickness=80,
size_factor=1,
mover=transform_bounce(
bounds=self.bounds,
velocity=(0.1, 0.5),
x_factor=(0.5, 1),
y_factor=(0.1, 0.3),
),
)
]
def ChaseCircleLine(self) -> List[Effect]:
return [
ChaseCircle(
bounds=self.bounds,
colors=(
color_wheel(increase=(75 if self.beat_reactive else 0)),
color_wheel(hue=180, increase=(75 if self.beat_reactive else 0)),
),
on_beat_color=self.beat_reactive,
size=int(self.bounds.height * 0.7),
rot_speed=-20,
thickness=80,
size_factor=0.2,
mover=transform_bounce(
bounds=self.bounds,
velocity=(0.1, 0.5),
x_factor=(0.5, 1),
y_factor=(0.1, 0.3),
),
)
]
# def Rectangle(self) -> List[Effect]:
# return [
# Rectangle(
# bounds=self.bounds,
# color=color_wheel(increase=(75 if self.beat_reactive else 1)),
# size=int(self.bounds.height*0.9),
# aspect=1.0,
# rot_speed=0.5,
# thickness=80,
# mover=transform_bounce(
# bounds=self.bounds,
# velocity=(0.1, 0.5),
# x_factor=(0.5, 1),
# y_factor=(0.1, 0.3),
# ),
# )
# ]