release candidate 1

This commit is contained in:
Linus Vogel 2025-12-06 17:37:11 +01:00
parent 8025514ab3
commit bb4bbbafdc
7 changed files with 85 additions and 30 deletions

1
.idea/workspace.xml generated
View File

@ -6,7 +6,6 @@
<component name="ChangeListManager"> <component name="ChangeListManager">
<list default="true" id="ae2847d5-ce86-4d84-8e66-f1369f1438e2" name="Changes" comment=""> <list default="true" id="ae2847d5-ce86-4d84-8e66-f1369f1438e2" name="Changes" comment="">
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" /> <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/starsky_presenter/resources/objects.yml" beforeDir="false" afterPath="$PROJECT_DIR$/src/starsky_presenter/resources/objects.yml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/starsky_presenter/resources/scenes.yml" beforeDir="false" afterPath="$PROJECT_DIR$/src/starsky_presenter/resources/scenes.yml" afterDir="false" /> <change beforePath="$PROJECT_DIR$/src/starsky_presenter/resources/scenes.yml" beforeDir="false" afterPath="$PROJECT_DIR$/src/starsky_presenter/resources/scenes.yml" afterDir="false" />
</list> </list>
<option name="SHOW_DIALOG" value="false" /> <option name="SHOW_DIALOG" value="false" />

View File

@ -4,12 +4,13 @@ from time import time
class Controller(QObject): class Controller(QObject):
def __init__(self, window, screen, parent=None): def __init__(self, window, screen, max_scene, parent=None):
super().__init__(parent) super().__init__(parent)
self.window = window self.window = window
self.last_close_press = 0 self.last_close_press = 0
self.successful_clicks = 0 self.successful_clicks = 0
self.screen = screen self.screen = screen
self.max_scene = max_scene
@pyqtSlot() @pyqtSlot()
def close_application(self): def close_application(self):
@ -26,6 +27,8 @@ class Controller(QObject):
@pyqtSlot(int) @pyqtSlot(int)
def select_scene(self, scene: int): def select_scene(self, scene: int):
if scene >= self.max_scene:
return
self.screen.last_scene = self.screen.active_scene self.screen.last_scene = self.screen.active_scene
self.screen.active_scene = scene self.screen.active_scene = scene
self.screen.scene_time = 0 self.screen.scene_time = 0

View File

@ -8,12 +8,12 @@ from starsky_presenter.projection.screen import Screen
class ControlWindow: class ControlWindow:
def __init__(self, screen): def __init__(self, screen, max_scene):
self.app = QGuiApplication([]) self.app = QGuiApplication([])
self.running = True self.running = True
self.engine = QQmlApplicationEngine(self.app) self.engine = QQmlApplicationEngine(self.app)
self.controller = Controller(self, screen) self.controller = Controller(self, screen, max_scene)
self.engine.quit.connect(self.app.quit) self.engine.quit.connect(self.app.quit)
self.engine.rootContext().setContextProperty("controller_backend", self.controller) self.engine.rootContext().setContextProperty("controller_backend", self.controller)
self.engine.load(f"{Path(__file__).parent.parent}/resources/main_window.qml") self.engine.load(f"{Path(__file__).parent.parent}/resources/main_window.qml")

View File

@ -30,10 +30,15 @@ def cli_main():
scenes = yaml.safe_load(reader.open_resource('resources/scenes.yml')) scenes = yaml.safe_load(reader.open_resource('resources/scenes.yml'))
objects = yaml.safe_load(reader.open_resource('resources/objects.yml')) objects = yaml.safe_load(reader.open_resource('resources/objects.yml'))
scene_data = [{ obj['sid']: deepcopy(obj) for obj in objects["stars"] }] + [ scene_data = [
{ obj['sid']: dict_update(obj, scenes[i][obj['sid']]) if scenes[i] and obj['sid'] in scenes[i] else deepcopy(obj) for obj in objects["stars"] } dict_update(
{ obj['sid']: dict_update(obj, scenes[i][obj['sid']]) if scenes[i] and obj['sid'] in scenes[i] else deepcopy(obj) for obj in objects["stars"] },
{
'transition': scenes[i]['transition'],
}
)
if i < len(scenes) else { obj['sid']: deepcopy(obj) for obj in objects["stars"] } if i < len(scenes) else { obj['sid']: deepcopy(obj) for obj in objects["stars"] }
for i in range(0,8) for i in range(0,9)
] ]
star_references = {} star_references = {}
@ -57,17 +62,24 @@ def cli_main():
# load the background image # load the background image
background = pygame.image.load(reader.open_resource(f"resources/{objects['background']}")) background = pygame.image.load(reader.open_resource(f"resources/{objects['background']}"))
screen = Screen(stars, background) screen = Screen(stars, background, objects['framerate'])
control_window = ControlWindow(screen) control_window = ControlWindow(screen, len(scenes))
last_time = time() last_time = time()
frame_count = 0
fps_update = objects['framerate']
star_time = time()
while control_window.is_running(): while control_window.is_running():
control_window.process_events() control_window.process_events()
screen.update(scene_data) screen.update(scene_data)
if frame_count % fps_update == 0:
now = time() now = time()
print(f"{1/(now - last_time):.02f} fps") print(f"{time() - star_time:.3f}s: {1/((now - last_time) / fps_update):.02f} fps")
last_time = now last_time = now
frame_count = 0
frame_count += 1
screen.close() screen.close()

View File

@ -7,6 +7,20 @@ from math import sin, cos, pi
from time import time, sleep from time import time, sleep
from random import random from random import random
INTERPOLATION = {
'sin2': lambda x: sin(x) ** 2,
'sin': lambda x: sin(x),
'cos': lambda x: 1 - cos(x),
'lin': lambda x: x
}
FADE = {
(True, True): lambda x: sin(x) ** 2, # fade both
(True, False): lambda x: 1 - cos(x), # fade in
(False, True): lambda x: sin(x), # fade out
(False, False): lambda x: x / (pi/2) # linear
}
class Star: class Star:
def __init__(self, sid: str, x: int, y: int, alpha: float, rot: float, scale: float, offset: float, image: pygame.Surface): def __init__(self, sid: str, x: int, y: int, alpha: float, rot: float, scale: float, offset: float, image: pygame.Surface):
self.sid = sid self.sid = sid
@ -20,7 +34,7 @@ class Star:
class Screen: class Screen:
def __init__(self, stars: list[Star], background: Surface | None) -> None: def __init__(self, stars: list[Star], background: Surface | None, framerate: float = 30) -> None:
if not pygame.get_init(): if not pygame.get_init():
pygame.init() pygame.init()
self.screen = pygame.display.set_mode((1920, 1080), display=1, flags=pygame.FULLSCREEN | pygame.DOUBLEBUF | pygame.WINDOWTAKEFOCUS) self.screen = pygame.display.set_mode((1920, 1080), display=1, flags=pygame.FULLSCREEN | pygame.DOUBLEBUF | pygame.WINDOWTAKEFOCUS)
@ -31,6 +45,8 @@ class Screen:
self.active_scene = 0 self.active_scene = 0
self.last_scene = 0 self.last_scene = 0
self.scene_time: float = 0 self.scene_time: float = 0
self.framerate: float = framerate
self.overlay = pygame.surface.Surface(self.screen.get_size(), depth=32)
if background: if background:
ratio_x = self.screen.get_width() / background.get_width() ratio_x = self.screen.get_width() / background.get_width()
ratio_y = self.screen.get_height() / background.get_height() ratio_y = self.screen.get_height() / background.get_height()
@ -48,17 +64,23 @@ class Screen:
def update(self, scene_data): def update(self, scene_data):
if not self.background:
self.screen.fill((0, 0, 0)) self.screen.fill((0, 0, 0))
now = time() now = time()
delta = now - self.last delta = now - self.last
self.last = now self.last = now
self.scene_time += delta self.scene_time += delta
weight = sin(min(self.scene_time, pi/2)) ** 2 fade_in = scene_data[self.active_scene]['transition']['fade_in']
fade_out = scene_data[self.active_scene]['transition']['fade_out']
t = FADE[(fade_in, fade_out)](min(self.scene_time / scene_data[self.active_scene]['transition']['t'], 1) * pi/2) * pi/2
weight_x = INTERPOLATION[scene_data[self.active_scene]['transition']['x']](t)
weight_y = INTERPOLATION[scene_data[self.active_scene]['transition']['y']](t)
weight = INTERPOLATION['sin2'](t)
def update_star_scene(star, old, new, weight): def update_star_scene(star, old, new):
star.x = weight*new[star.sid]['x'] + (1-weight)*old[star.sid]['x'] star.x = weight_x*new[star.sid]['x'] + (1-weight_x)*old[star.sid]['x']
star.y = weight*new[star.sid]['y'] + (1-weight)*old[star.sid]['y'] star.y = weight_y*new[star.sid]['y'] + (1-weight_y)*old[star.sid]['y']
star.rot = weight*new[star.sid]['rot'] + (1-weight)*old[star.sid]['rot'] star.rot = weight*new[star.sid]['rot'] + (1-weight)*old[star.sid]['rot']
star.scale = weight*new[star.sid]['scale'] + (1-weight)*old[star.sid]['scale'] star.scale = weight*new[star.sid]['scale'] + (1-weight)*old[star.sid]['scale']
@ -69,7 +91,7 @@ class Screen:
# draw all the star objects # draw all the star objects
for star in self.stars: for star in self.stars:
update_star_scene(star, scene_data[self.last_scene], scene_data[self.active_scene], weight) update_star_scene(star, scene_data[self.last_scene], scene_data[self.active_scene])
star.alpha += star.rot * delta star.alpha += star.rot * delta
computed_scale = star.scale * (self.screen.get_width() / star.image.get_width() / 100) computed_scale = star.scale * (self.screen.get_width() / star.image.get_width() / 100)
scaled = transform.rotozoom(star.image, star.alpha, computed_scale) scaled = transform.rotozoom(star.image, star.alpha, computed_scale)
@ -78,12 +100,11 @@ class Screen:
self.screen.blit(scaled, pos) self.screen.blit(scaled, pos)
overlay = pygame.surface.Surface((1920, 1080), depth=32) self.overlay.set_alpha(int(255 * (1 - self.brightness)))
overlay.set_alpha(int(255 * (1 - self.brightness))) self.screen.blit(self.overlay, (0, 0))
self.screen.blit(overlay, (0, 0))
pygame.display.flip() pygame.display.flip()
self.clock.tick(60) self.clock.tick(self.framerate)
def close(self): def close(self):
pygame.quit() pygame.quit()

View File

@ -2,9 +2,10 @@ stars:
- sid: star-1 - sid: star-1
x: 0.1 x: 0.1
y: 0.1 y: 0.1
scale: 2 scale: 5
alpha: 0 alpha: 0
rot: 30 rot: 5
offset: 0 offset: 0
image: nice-star-1.png image: nice-star-1.png
background: background-01.jpg background: background-01.jpg
framerate: 30

View File

@ -1,8 +1,27 @@
- star-1: - star-1:
x: 0.5 x: 1.1
y: 2 y: 1.1
transition: 5 transition:
t: 5
fade_in: true
fade_out: false
x: sin
y: cos
- star-1: - star-1:
x: 0.5 x: 0.5
y: 0.5 y: 0.5
transition: 1 transition:
t: 5
fade_in: false
fade_out: true
x: cos
y: sin
- star-1:
x: -0.1
y: 1.1
transition:
t: 5
fade_in: true
fade_out: false
x: sin
y: cos