From 974ed1de0b1c33322a56692508e0d65b6b1d845e Mon Sep 17 00:00:00 2001 From: Linus Vogel Date: Sat, 6 Dec 2025 17:37:11 +0100 Subject: [PATCH] release candidate 1 --- .idea/workspace.xml | 4 ++ .../controller/controller.py | 5 ++- src/starsky_presenter/controller/window.py | 4 +- src/starsky_presenter/entry.py | 28 ++++++++---- src/starsky_presenter/projection/screen.py | 43 ++++++++++++++----- src/starsky_presenter/resources/objects.yml | 5 ++- src/starsky_presenter/resources/scenes.yml | 27 ++++++++++-- 7 files changed, 88 insertions(+), 28 deletions(-) diff --git a/.idea/workspace.xml b/.idea/workspace.xml index ebe3fd9..8969bfb 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -6,6 +6,10 @@ + + + + diff --git a/src/starsky_presenter/controller/controller.py b/src/starsky_presenter/controller/controller.py index 945abad..6e47783 100644 --- a/src/starsky_presenter/controller/controller.py +++ b/src/starsky_presenter/controller/controller.py @@ -4,12 +4,13 @@ from time import time class Controller(QObject): - def __init__(self, window, screen, parent=None): + def __init__(self, window, screen, max_scene, parent=None): super().__init__(parent) self.window = window self.last_close_press = 0 self.successful_clicks = 0 self.screen = screen + self.max_scene = max_scene @pyqtSlot() def close_application(self): @@ -26,6 +27,8 @@ class Controller(QObject): @pyqtSlot(int) def select_scene(self, scene: int): + if scene >= self.max_scene: + return self.screen.last_scene = self.screen.active_scene self.screen.active_scene = scene self.screen.scene_time = 0 \ No newline at end of file diff --git a/src/starsky_presenter/controller/window.py b/src/starsky_presenter/controller/window.py index 8bf8fb7..9ab831a 100644 --- a/src/starsky_presenter/controller/window.py +++ b/src/starsky_presenter/controller/window.py @@ -8,12 +8,12 @@ from starsky_presenter.projection.screen import Screen class ControlWindow: - def __init__(self, screen): + def __init__(self, screen, max_scene): self.app = QGuiApplication([]) self.running = True 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.rootContext().setContextProperty("controller_backend", self.controller) self.engine.load(f"{Path(__file__).parent.parent}/resources/main_window.qml") diff --git a/src/starsky_presenter/entry.py b/src/starsky_presenter/entry.py index 6cf8c8f..7408e6e 100644 --- a/src/starsky_presenter/entry.py +++ b/src/starsky_presenter/entry.py @@ -30,10 +30,15 @@ def cli_main(): scenes = yaml.safe_load(reader.open_resource('resources/scenes.yml')) objects = yaml.safe_load(reader.open_resource('resources/objects.yml')) - scene_data = [{ obj['sid']: deepcopy(obj) for obj in objects["stars"] }] + [ - { 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"] } + scene_data = [ + 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"] } - for i in range(0,8) + for i in range(0,9) ] star_references = {} @@ -57,17 +62,24 @@ def cli_main(): # load the background image background = pygame.image.load(reader.open_resource(f"resources/{objects['background']}")) - screen = Screen(stars, background) - control_window = ControlWindow(screen) + screen = Screen(stars, background, objects['framerate']) + control_window = ControlWindow(screen, len(scenes)) last_time = time() + frame_count = 0 + fps_update = objects['framerate'] + star_time = time() while control_window.is_running(): control_window.process_events() screen.update(scene_data) - now = time() - print(f"{1/(now - last_time):.02f} fps") - last_time = now + if frame_count % fps_update == 0: + now = time() + print(f"{time() - star_time:.3f}s: {1/((now - last_time) / fps_update):.02f} fps") + last_time = now + frame_count = 0 + + frame_count += 1 screen.close() diff --git a/src/starsky_presenter/projection/screen.py b/src/starsky_presenter/projection/screen.py index 5071680..d19f059 100644 --- a/src/starsky_presenter/projection/screen.py +++ b/src/starsky_presenter/projection/screen.py @@ -7,6 +7,20 @@ from math import sin, cos, pi from time import time, sleep 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: def __init__(self, sid: str, x: int, y: int, alpha: float, rot: float, scale: float, offset: float, image: pygame.Surface): self.sid = sid @@ -20,7 +34,7 @@ class Star: 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(): pygame.init() 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.last_scene = 0 self.scene_time: float = 0 + self.framerate: float = framerate + self.overlay = pygame.surface.Surface(self.screen.get_size(), depth=32) if background: ratio_x = self.screen.get_width() / background.get_width() ratio_y = self.screen.get_height() / background.get_height() @@ -48,17 +64,23 @@ class Screen: def update(self, scene_data): - self.screen.fill((0, 0, 0)) + if not self.background: + self.screen.fill((0, 0, 0)) now = time() delta = now - self.last self.last = now 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): - star.x = weight*new[star.sid]['x'] + (1-weight)*old[star.sid]['x'] - star.y = weight*new[star.sid]['y'] + (1-weight)*old[star.sid]['y'] + def update_star_scene(star, old, new): + star.x = weight_x*new[star.sid]['x'] + (1-weight_x)*old[star.sid]['x'] + 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.scale = weight*new[star.sid]['scale'] + (1-weight)*old[star.sid]['scale'] @@ -69,7 +91,7 @@ class Screen: # draw all the star objects 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 computed_scale = star.scale * (self.screen.get_width() / star.image.get_width() / 100) scaled = transform.rotozoom(star.image, star.alpha, computed_scale) @@ -78,12 +100,11 @@ class Screen: self.screen.blit(scaled, pos) - overlay = pygame.surface.Surface((1920, 1080), depth=32) - overlay.set_alpha(int(255 * (1 - self.brightness))) - self.screen.blit(overlay, (0, 0)) + self.overlay.set_alpha(int(255 * (1 - self.brightness))) + self.screen.blit(self.overlay, (0, 0)) pygame.display.flip() - self.clock.tick(60) + self.clock.tick(self.framerate) def close(self): pygame.quit() \ No newline at end of file diff --git a/src/starsky_presenter/resources/objects.yml b/src/starsky_presenter/resources/objects.yml index 718a407..ea8d298 100644 --- a/src/starsky_presenter/resources/objects.yml +++ b/src/starsky_presenter/resources/objects.yml @@ -2,9 +2,10 @@ stars: - sid: star-1 x: 0.1 y: 0.1 - scale: 2 + scale: 5 alpha: 0 rot: 30 offset: 0 image: nice-star-1.png -background: background-01.jpg \ No newline at end of file +background: background-01.jpg +framerate: 30 \ No newline at end of file diff --git a/src/starsky_presenter/resources/scenes.yml b/src/starsky_presenter/resources/scenes.yml index 79ebcb5..69f8776 100644 --- a/src/starsky_presenter/resources/scenes.yml +++ b/src/starsky_presenter/resources/scenes.yml @@ -1,8 +1,27 @@ - star-1: - x: 0.5 - y: 2 - transition: 5 + x: 1.1 + y: 1.1 + transition: + t: 2 + fade_in: true + fade_out: false + x: sin + y: cos - star-1: x: 0.5 y: 0.5 - transition: 1 + transition: + t: 2 + fade_in: false + fade_out: true + x: cos + y: sin +- star-1: + x: -0.1 + y: 1.1 + transition: + t: 2 + fade_in: true + fade_out: false + x: sin + y: cos \ No newline at end of file