Browse Source

Improve `pre_export()` generators.

It is now possible to write
```python
my_object = yield create_something()
```
to ensure that temporary objects are always managed by the exporter. Previously, the more verbose
```python
my_object = create_something()
yield my_object
```
was needed.
pull/374/head
Adam Johnson 1 year ago
parent
commit
03615c30b5
Signed by: Hoikas
GPG Key ID: 0B6515D6FF6F271E
  1. 42
      korman/exporter/convert.py

42
korman/exporter/convert.py

@ -18,6 +18,7 @@ import bpy
from collections import defaultdict from collections import defaultdict
from contextlib import ExitStack from contextlib import ExitStack
import functools import functools
import inspect
from pathlib import Path from pathlib import Path
from typing import * from typing import *
@ -459,10 +460,14 @@ class Exporter:
if hasattr(temporary, "__enter__"): if hasattr(temporary, "__enter__"):
ctx_temporary = self.exit_stack.enter_context(temporary) ctx_temporary = self.exit_stack.enter_context(temporary)
if ctx_temporary is not None: if ctx_temporary is not None:
handle_temporary(ctx_temporary, parent) return handle_temporary(ctx_temporary, parent)
else: else:
raise RuntimeError("Temporary object of type '{}' generated by '{}' was unhandled".format(temporary.__class__, parent.name)) raise RuntimeError("Temporary object of type '{}' generated by '{}' was unhandled".format(temporary.__class__, parent.name))
@handle_temporary.register(utils.BMeshObject)
def _(temporary, parent):
return handle_temporary(temporary.release(), parent)
@handle_temporary.register(bpy.types.Object) @handle_temporary.register(bpy.types.Object)
def _(temporary, parent): def _(temporary, parent):
self.exit_stack.enter_context(TemporaryObject(temporary, bpy.data.objects.remove)) self.exit_stack.enter_context(TemporaryObject(temporary, bpy.data.objects.remove))
@ -483,6 +488,7 @@ class Exporter:
for mod in temporary.plasma_modifiers.modifiers: for mod in temporary.plasma_modifiers.modifiers:
mod.sanity_check() mod.sanity_check()
do_pre_export(temporary) do_pre_export(temporary)
return temporary
@handle_temporary.register(bpy.types.NodeTree) @handle_temporary.register(bpy.types.NodeTree)
def _(temporary, parent): def _(temporary, parent):
@ -491,15 +497,41 @@ class Exporter:
if temporary.bl_idname == "PlasmaNodeTree": if temporary.bl_idname == "PlasmaNodeTree":
parent_so = self.mgr.find_create_object(plSceneObject, bl=parent) parent_so = self.mgr.find_create_object(plSceneObject, bl=parent)
self.want_node_trees[temporary.name].add((parent, parent_so)) self.want_node_trees[temporary.name].add((parent, parent_so))
return temporary
def do_pre_export(bo): def do_pre_export(bo):
for mod in bo.plasma_modifiers.modifiers: for mod in bo.plasma_modifiers.modifiers:
proc = getattr(mod, "pre_export", None) proc = getattr(mod, "pre_export", None)
if proc is not None: if proc is not None:
result = proc(self, bo) # pre_export() should be a *generator*. Generators are bidirectional, although
if result is not None: # trivial usages simply yield values for the consumer. What we want to do here
for i in filter(None, result): # is use the bidirectional nature of generators to simplify the code in pre_export().
handle_temporary(i, bo) # We will pump the pre_export generator. With each pump, we will send the generator
# the very thing it gave us. That way, if pre_export needs to do some work on
# the object it generated, then it can do:
# ```
# my_object = yield create_something()
# my_object.foo = bar
# ```
# instead of the more verbose
# ```
# my_object = create_something()
# yield my_object
# my_object.foo = bar
# ```
assert inspect.isgeneratorfunction(proc), "pre_export should be a generator function"
pre_result = proc(self, bo)
try:
gen_result = None
while True:
gen_result = pre_result.send(gen_result)
if gen_result is not None:
gen_result = handle_temporary(gen_result, bo)
except StopIteration as e:
if e.value is not None:
handle_temporary(e.value, bo)
finally:
pre_result.close()
with indent(): with indent():
for bl_obj in self._objects: for bl_obj in self._objects:

Loading…
Cancel
Save