Mercurial > code > home > repos > light9
annotate blender/time_sync/blender_time.py @ 2455:2d454737a916
split blender code to new file
author | drewp@bigasterisk.com |
---|---|
date | Tue, 20 May 2025 09:24:35 -0700 |
parents | blender/time_sync/time_from_graph.py@405abed9a45c |
children | d94480bfb179 |
rev | line source |
---|---|
2455 | 1 from dataclasses import dataclass |
2 from typing import Callable | |
2432 | 3 |
2455 | 4 import bpy |
5 from bpy.app.handlers import persistent | |
2432 | 6 |
7 from light9.run_local import log | |
2455 | 8 |
9 UPDATE_PERIOD = 1 / 20 | |
2432 | 10 |
11 | |
12 def clamp(lo, hi, x): | |
13 return max(lo, min(hi, x)) | |
14 | |
15 | |
2455 | 16 class _TimeEvent(): |
17 pass | |
18 | |
19 | |
20 class SceneLoaded(_TimeEvent): | |
21 pass | |
22 | |
23 | |
24 @dataclass | |
25 class PausedGotoTime(_TimeEvent): | |
26 t: float | |
2432 | 27 |
28 | |
2455 | 29 @dataclass |
30 class PlayingGotoTime(_TimeEvent): | |
31 t: float | |
32 | |
33 | |
34 class BlenderTime: | |
35 """all methods to run in main thread""" | |
2432 | 36 |
2455 | 37 def __init__(self, onEvent: Callable[[_TimeEvent], None]): |
38 self._onEvent = onEvent | |
2432 | 39 self.lastSetFrame = -1 |
2455 | 40 |
41 def start(self): | |
42 bpy.app.handlers.load_post.append(self._on_load_post) | |
43 bpy.app.handlers.frame_change_post.append(self._on_frame_change_post) | |
2454 | 44 |
2453
b23afde50bc2
blender addons get thier own pdm setup for now. fix time_from_graph startup race
drewp@bigasterisk.com
parents:
2436
diff
changeset
|
45 # need persistent because `blender --addons ...` seems to start addon |
b23afde50bc2
blender addons get thier own pdm setup for now. fix time_from_graph startup race
drewp@bigasterisk.com
parents:
2436
diff
changeset
|
46 # before loading scene. |
b23afde50bc2
blender addons get thier own pdm setup for now. fix time_from_graph startup race
drewp@bigasterisk.com
parents:
2436
diff
changeset
|
47 bpy.app.timers.register(self.update, persistent=True) |
2432 | 48 |
2455 | 49 self.emitEvent(SceneLoaded()) |
2432 | 50 |
2455 | 51 def setSceneDuration(self, duration: float): |
52 self.duration = duration | |
2432 | 53 scene = bpy.context.scene |
54 fps = scene.render.fps | |
55 scene.frame_start = 0 | |
56 scene.frame_end = int(duration * fps) | |
2455 | 57 |
58 def frameDuration(self): | |
59 return | |
60 # todo: need to be in screen context or something | |
61 context_override = bpy.context.copy() | |
62 # context_override["selected_objects"] = list(context.scene.objects) | |
63 with bpy.context.temp_override(**context_override): | |
64 bpy.ops.action.view_all() | |
65 | |
66 def setCurrentTime(self, t: float): | |
67 scene = bpy.context.scene | |
68 fps = scene.render.fps | |
69 fr = int(clamp(t, 0, self.duration) * fps) | |
2432 | 70 self.lastSetFrame = fr |
71 scene.frame_set(fr) | |
72 | |
2455 | 73 def setBlenderTime(self, t: float, duration: float): |
74 log.info(f'set blender time to {t:.2f}') | |
75 self.setSceneDuration(duration) | |
76 self.frameDuration() | |
77 self.setCurrentTime(t) | |
78 | |
79 def emitEvent(self, event: _TimeEvent): | |
80 log.info(f'🌹 emitEvent {event}') | |
81 self._onEvent(event) | |
2432 | 82 |
83 @persistent | |
2455 | 84 def update(self): |
85 if 0: | |
86 if self.playing: | |
87 with self.lock: | |
88 t = self.currentTime() | |
89 if t is not None: | |
90 self.blenderTime.setBlenderTime(t, self.duration) | |
91 return UPDATE_PERIOD | |
2432 | 92 |
2455 | 93 @persistent |
94 def _on_load_post(self, scene, deps): | |
95 self.emitEvent(SceneLoaded()) | |
96 | |
97 @persistent | |
98 def _on_frame_change_post(self, scene, deps): | |
99 # if scene.frame_current == self.lastSetFrame: | |
100 # return | |
101 # blender requested this frame change, either playing or paused (scrubbing timeline) | |
102 self.lastSetFrame = scene.frame_current | |
103 t = round(scene.frame_current / scene.render.fps, 3) | |
104 if bpy.context.screen.is_animation_playing and not bpy.context.screen.is_scrubbing: | |
105 self.emitEvent(PlayingGotoTime(t=t)) | |
2454 | 106 else: |
2455 | 107 self.emitEvent(PausedGotoTime(t=t)) |