Mercurial > code > home > repos > light9
comparison blender/time_sync/time_from_graph.py @ 2454:405abed9a45c
fix up asyncio-in-bg-thread sorcery
author | drewp@bigasterisk.com |
---|---|
date | Mon, 19 May 2025 21:25:32 -0700 |
parents | b23afde50bc2 |
children | 2d454737a916 |
comparison
equal
deleted
inserted
replaced
2453:b23afde50bc2 | 2454:405abed9a45c |
---|---|
1 import asyncio | |
1 import threading | 2 import threading |
2 import time | 3 import time |
4 from typing import Coroutine, cast | |
3 | 5 |
4 import bpy # type: ignore | 6 import bpy # type: ignore |
5 from bpy.app.handlers import persistent # type: ignore | 7 from bpy.app.handlers import persistent # type: ignore |
6 from light9_sync.asyncio_thread import startLoopInThread | 8 from ..asyncio_thread import startLoopInThread |
7 from rdfdb.syncedgraph.syncedgraph import SyncedGraph | 9 from rdfdb.syncedgraph.syncedgraph import SyncedGraph |
10 from rdflib import URIRef | |
11 from rdflib.graph import _ContextType | |
8 | 12 |
9 from light9 import networking | 13 from light9 import networking, showconfig |
10 from light9.namespaces import L9 | 14 from light9.namespaces import L9 |
15 from light9.newtypes import decimalLiteral | |
11 from light9.run_local import log | 16 from light9.run_local import log |
12 from light9.typedgraph import typedValue | 17 from light9.typedgraph import typedValue |
13 | 18 |
14 | 19 |
15 def clamp(lo, hi, x): | 20 def clamp(lo, hi, x): |
29 | 34 |
30 def __init__(self): | 35 def __init__(self): |
31 # main thread | 36 # main thread |
32 self.lastSetFrame = -1 | 37 self.lastSetFrame = -1 |
33 self.lastGraphFrame = -1 | 38 self.lastGraphFrame = -1 |
34 startLoopInThread(self.task()) | 39 show = showconfig.showUri() |
40 self.ctx = cast(_ContextType, (URIRef(show + '/ascoltami'))) | |
41 log.debug('🚋3 startLoopInThread') | |
42 self._loop = startLoopInThread(self.task()) | |
43 | |
35 # need persistent because `blender --addons ...` seems to start addon | 44 # need persistent because `blender --addons ...` seems to start addon |
36 # before loading scene. | 45 # before loading scene. |
37 bpy.app.timers.register(self.update, persistent=True) | 46 bpy.app.timers.register(self.update, persistent=True) |
38 bpy.app.handlers.frame_change_post.append(self.on_frame_change_post) | 47 bpy.app.handlers.frame_change_post.append(self.on_frame_change_post) |
48 log.info('🚋10 Sync initd') | |
39 | 49 |
40 ## updates from graph -> self | 50 ## updates from graph -> self |
41 | 51 |
52 def runInBackgroundLoop(self, f: Coroutine): | |
53 asyncio.run_coroutine_threadsafe(f, self._loop) | |
54 | |
55 | |
42 async def task(self): | 56 async def task(self): |
43 # bg thread with asyncio loop | 57 # bg thread with asyncio loop |
58 log.info('🚋11 start SyncedGraph') | |
44 self.graph = SyncedGraph(networking.rdfdb.url, "time_sync") | 59 self.graph = SyncedGraph(networking.rdfdb.url, "time_sync") |
45 self.graph.addHandler(self.syncFromGraph) | 60 self.graph.addHandler(self.syncFromGraph) |
46 | 61 |
47 def syncFromGraph(self): | 62 def syncFromGraph(self): |
48 # bg thread | 63 # bg thread |
61 log.warn('no time data') | 76 log.warn('no time data') |
62 return None | 77 return None |
63 | 78 |
64 ## graph time -> blender time | 79 ## graph time -> blender time |
65 | 80 |
66 # @persistent | 81 @persistent |
67 def update(self): | 82 def update(self): |
68 # main thread? wherever blender runs timers | 83 # main thread? wherever blender runs timers |
69 if self.playing: | 84 if self.playing: |
70 with self.lock: | 85 with self.lock: |
71 t = self.currentTime() | 86 t = self.currentTime() |
88 def on_frame_change_post(self, scene, deps): | 103 def on_frame_change_post(self, scene, deps): |
89 if scene.frame_current != self.lastSetFrame: | 104 if scene.frame_current != self.lastSetFrame: |
90 # self.setGraphTime(scene.frame_current / scene.render.fps, self.duration) | 105 # self.setGraphTime(scene.frame_current / scene.render.fps, self.duration) |
91 self.lastSetFrame = scene.frame_current | 106 self.lastSetFrame = scene.frame_current |
92 t = scene.frame_current / scene.render.fps | 107 t = scene.frame_current / scene.render.fps |
93 self.setInGraph(t) | 108 self.runInBackgroundLoop(self.setInGraph(t, bpy.context.screen.is_animation_playing)) |
94 | 109 |
95 def setInGraph(self, t: float): | 110 async def setInGraph(self, t: float, isBlenderPlaying: bool): |
96 log.warning(f'todo: set graph to {t:.2f}') | 111 log.info(f'set graph time to {t:.2f}') |
112 if isBlenderPlaying: | |
113 log.info(' playing mode') | |
114 p = self.graph.getObjectPatch(self.ctx, L9['ascoltami'], L9['wallStartTime'], decimalLiteral(t)) | |
115 else: | |
116 log.info(' paused mode') | |
117 p = self.graph.getObjectPatch(self.ctx, L9['ascoltami'], L9['pausedSongTime'], decimalLiteral(t)) | |
118 | |
119 await self.graph.patch(p) |