# HG changeset patch # User drewp@bigasterisk.com # Date 2024-05-29 00:56:16 # Node ID 9b101d8bd7ea0278db0d551dc7f36c7826b27530 # Parent ffa69645e9dcd0e8ff25cd45e2742478a44b4a16 discover annotated lights in blender; send their color to the graph (temporary stmt) diff --git a/src/light9/blender/light_control/__init__.py b/src/light9/blender/light_control/__init__.py --- a/src/light9/blender/light_control/__init__.py +++ b/src/light9/blender/light_control/__init__.py @@ -2,12 +2,6 @@ watch blender lights, output to real lights """ -import time -from typing import cast - -import bpy # type: ignore -from bpy.app.handlers import persistent - sender: object = None @@ -17,12 +11,6 @@ def register(): sender = Sender() - # @persistent - # def fcp(scene): - # cast(Sender, sender).on_frame_change_post(scene) - - # bpy.app.handlers.frame_change_post.append(fcp) - def unregister(): raise NotImplementedError diff --git a/src/light9/blender/light_control/send_to_collector.py b/src/light9/blender/light_control/send_to_collector.py --- a/src/light9/blender/light_control/send_to_collector.py +++ b/src/light9/blender/light_control/send_to_collector.py @@ -1,7 +1,81 @@ +import asyncio +import logging +from dataclasses import dataclass, field + +import bpy # type: ignore +from light9.blender.time_sync.time_from_graph import clamp +from light9.effect.effecteval import literalColor +from rdfdb.patch import Patch +from rdfdb.syncedgraph.syncedgraph import SyncedGraph +from rdflib import Literal, URIRef + +from light9 import networking +from light9.blender.asyncio_thread import startLoopInThread +from light9.namespaces import L9 +from light9.newtypes import DeviceUri +from light9.showconfig import showUri + +log = logging.getLogger('sendcoll') + +UPDATE_PERIOD = 1 / 20 + + +@dataclass +class BlenderDev: + ctx: URIRef + obj: bpy.types.Object + uri: DeviceUri + color: tuple[float, float, float] = (0, 0, 0) + + def updateColor(self): + self.color = self.obj.data.color + + def makePatch(self, graph: SyncedGraph) -> Patch: + c = literalColor(*[clamp(x, 0, 1) for x in self.color]) + return graph.getObjectPatch(self.ctx, self.uri, L9['blenderColor'], c) + + +@dataclass class Sender: + syncedObjects: dict[str, BlenderDev] = field(default_factory=dict) - def blenderTime(self) -> float: - return -55 + ctx = URIRef(showUri() + '/blender') + + def __post_init__(self): + bpy.app.timers.register(self.findLightsInScene, first_interval=0.1) # todo: what event to use? + startLoopInThread(self.task()) + + async def task(self): + graph = SyncedGraph(networking.rdfdb.url, "blender_light_control") + while True: + try: + p = Patch(addQuads=[], delQuads=[]) + for d in self.syncedObjects.values(): + p = p.update(d.makePatch(graph)) + if p: + await graph.patch(p) + except Exception: + log.error('skip', exc_info=True) + await asyncio.sleep(1) + await asyncio.sleep(UPDATE_PERIOD) - def on_frame_change_post(self, scene, *args): - print('ofcp',scene,args) + def findLightsInScene(self): + self.syncedObjects.clear() + for obj in bpy.data.objects: + if obj.get('l9dev'): + uri = DeviceUri(URIRef(obj['l9dev'])) + self.syncedObjects[obj.name] = BlenderDev(self.ctx, obj, uri) + log.info(f'found {self.syncedObjects[obj.name]}') + + self.watchForUpdates() + + def watchForUpdates(self): + bpy.app.handlers.depsgraph_update_post.append(self.onColorChanges) + bpy.app.handlers.frame_change_post.append(self.onColorChanges) + + def onColorChanges(self, scene, deps): + for obj in deps.objects: + dev = self.syncedObjects.get(obj.name) + if dev is None: + continue + dev.updateColor() diff --git a/src/light9/blender/time_sync/time_from_graph.py b/src/light9/blender/time_sync/time_from_graph.py --- a/src/light9/blender/time_sync/time_from_graph.py +++ b/src/light9/blender/time_sync/time_from_graph.py @@ -50,7 +50,7 @@ class Sync: self.wallStartTime = typedValue(float | None, self.graph, asco, L9['wallStartTime']) self.pausedSongTime = typedValue(float | None, self.graph, asco, L9['pausedSongTime']) self.duration = typedValue(float | None, self.graph, asco, L9['duration']) or 1.0 - self.playing = typedValue(bool, self.graph, asco, L9['playing']) + self.playing = typedValue(bool|None, self.graph, asco, L9['playing']) or False def currentTime(self) -> float | None: if self.wallStartTime is not None: @@ -92,4 +92,4 @@ class Sync: self.setInGraph(t) def setInGraph(self, t: float): - log.warning(f'todo: set graph to {t}') + log.warning(f'todo: set graph to {t:.2f}')